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:
Diffstat (limited to 'intern/cycles')
-rw-r--r--intern/cycles/CMakeLists.txt15
-rw-r--r--intern/cycles/app/CMakeLists.txt9
-rw-r--r--intern/cycles/app/cycles_server.cpp14
-rw-r--r--intern/cycles/app/cycles_standalone.cpp82
-rw-r--r--intern/cycles/app/cycles_xml.cpp43
-rw-r--r--intern/cycles/app/oiio_output_driver.cpp71
-rw-r--r--intern/cycles/app/oiio_output_driver.h42
-rw-r--r--intern/cycles/blender/CMakeLists.txt75
-rw-r--r--intern/cycles/blender/addon/camera.py84
-rw-r--r--intern/cycles/blender/addon/engine.py7
-rw-r--r--intern/cycles/blender/addon/presets.py8
-rw-r--r--intern/cycles/blender/addon/properties.py167
-rw-r--r--intern/cycles/blender/addon/ui.py160
-rw-r--r--intern/cycles/blender/addon/version_update.py13
-rw-r--r--intern/cycles/blender/blender_camera.cpp933
-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_geometry.cpp241
-rw-r--r--intern/cycles/blender/blender_gpu_display.cpp787
-rw-r--r--intern/cycles/blender/blender_gpu_display.h215
-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.cpp770
-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_particles.cpp94
-rw-r--r--intern/cycles/blender/blender_python.cpp1063
-rw-r--r--intern/cycles/blender/blender_session.cpp1113
-rw-r--r--intern/cycles/blender/blender_session.h175
-rw-r--r--intern/cycles/blender/blender_shader.cpp1553
-rw-r--r--intern/cycles/blender/blender_sync.cpp951
-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.h698
-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.cpp984
-rw-r--r--intern/cycles/blender/curves.cpp900
-rw-r--r--intern/cycles/blender/device.cpp124
-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.cpp1071
-rw-r--r--intern/cycles/blender/display_driver.h164
-rw-r--r--intern/cycles/blender/geometry.cpp265
-rw-r--r--intern/cycles/blender/id_map.h295
-rw-r--r--intern/cycles/blender/image.cpp226
-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.cpp1276
-rw-r--r--intern/cycles/blender/object.cpp802
-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.cpp124
-rw-r--r--intern/cycles/blender/output_driver.h40
-rw-r--r--intern/cycles/blender/particles.cpp94
-rw-r--r--intern/cycles/blender/pointcloud.cpp303
-rw-r--r--intern/cycles/blender/python.cpp1049
-rw-r--r--intern/cycles/blender/session.cpp1033
-rw-r--r--intern/cycles/blender/session.h166
-rw-r--r--intern/cycles/blender/shader.cpp1603
-rw-r--r--intern/cycles/blender/sync.cpp1004
-rw-r--r--intern/cycles/blender/sync.h284
-rw-r--r--intern/cycles/blender/texture.cpp57
-rw-r--r--intern/cycles/blender/texture.h32
-rw-r--r--intern/cycles/blender/util.h744
-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.txt52
-rw-r--r--intern/cycles/bvh/binning.cpp293
-rw-r--r--intern/cycles/bvh/binning.h115
-rw-r--r--intern/cycles/bvh/build.cpp1262
-rw-r--r--intern/cycles/bvh/build.h144
-rw-r--r--intern/cycles/bvh/bvh.cpp24
-rw-r--r--intern/cycles/bvh/bvh.h14
-rw-r--r--intern/cycles/bvh/bvh2.cpp115
-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.cpp1140
-rw-r--r--intern/cycles/bvh/bvh_build.h142
-rw-r--r--intern/cycles/bvh/bvh_embree.cpp727
-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.cpp874
-rw-r--r--intern/cycles/bvh/embree.h73
-rw-r--r--intern/cycles/bvh/metal.h35
-rw-r--r--intern/cycles/bvh/metal.mm33
-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.cpp49
-rw-r--r--intern/cycles/bvh/optix.h52
-rw-r--r--intern/cycles/bvh/params.h349
-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.cpp566
-rw-r--r--intern/cycles/bvh/split.h254
-rw-r--r--intern/cycles/bvh/unaligned.cpp165
-rw-r--r--intern/cycles/bvh/unaligned.h73
-rw-r--r--intern/cycles/cmake/external_libs.cmake31
-rw-r--r--intern/cycles/cmake/macros.cmake39
-rw-r--r--intern/cycles/device/CMakeLists.txt70
-rw-r--r--intern/cycles/device/cpu/device.cpp3
-rw-r--r--intern/cycles/device/cpu/device.h4
-rw-r--r--intern/cycles/device/cpu/device_impl.cpp58
-rw-r--r--intern/cycles/device/cpu/device_impl.h15
-rw-r--r--intern/cycles/device/cpu/kernel.cpp20
-rw-r--r--intern/cycles/device/cpu/kernel.h62
-rw-r--r--intern/cycles/device/cpu/kernel_function.h4
-rw-r--r--intern/cycles/device/cpu/kernel_thread_globals.cpp14
-rw-r--r--intern/cycles/device/cpu/kernel_thread_globals.h8
-rw-r--r--intern/cycles/device/cuda/device.cpp7
-rw-r--r--intern/cycles/device/cuda/device.h4
-rw-r--r--intern/cycles/device/cuda/device_impl.cpp72
-rw-r--r--intern/cycles/device/cuda/device_impl.h4
-rw-r--r--intern/cycles/device/cuda/graphics_interop.cpp19
-rw-r--r--intern/cycles/device/cuda/graphics_interop.h4
-rw-r--r--intern/cycles/device/cuda/kernel.h2
-rw-r--r--intern/cycles/device/cuda/queue.cpp22
-rw-r--r--intern/cycles/device/cuda/queue.h10
-rw-r--r--intern/cycles/device/denoise.cpp90
-rw-r--r--intern/cycles/device/denoise.h114
-rw-r--r--intern/cycles/device/device.cpp75
-rw-r--r--intern/cycles/device/device.h41
-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.h55
-rw-r--r--intern/cycles/device/device_kernel.cpp157
-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.cpp26
-rw-r--r--intern/cycles/device/hip/device.h4
-rw-r--r--intern/cycles/device/hip/device_impl.cpp307
-rw-r--r--intern/cycles/device/hip/device_impl.h11
-rw-r--r--intern/cycles/device/hip/graphics_interop.cpp22
-rw-r--r--intern/cycles/device/hip/graphics_interop.h9
-rw-r--r--intern/cycles/device/hip/kernel.cpp2
-rw-r--r--intern/cycles/device/hip/kernel.h2
-rw-r--r--intern/cycles/device/hip/queue.cpp85
-rw-r--r--intern/cycles/device/hip/queue.h13
-rw-r--r--intern/cycles/device/hip/util.h9
-rw-r--r--intern/cycles/device/kernel.cpp165
-rw-r--r--intern/cycles/device/kernel.h33
-rw-r--r--intern/cycles/device/memory.cpp246
-rw-r--r--intern/cycles/device/memory.h635
-rw-r--r--intern/cycles/device/metal/bvh.h71
-rw-r--r--intern/cycles/device/metal/bvh.mm1030
-rw-r--r--intern/cycles/device/metal/device.h37
-rw-r--r--intern/cycles/device/metal/device.mm136
-rw-r--r--intern/cycles/device/metal/device_impl.h168
-rw-r--r--intern/cycles/device/metal/device_impl.mm1017
-rw-r--r--intern/cycles/device/metal/kernel.h170
-rw-r--r--intern/cycles/device/metal/kernel.mm541
-rw-r--r--intern/cycles/device/metal/queue.h99
-rw-r--r--intern/cycles/device/metal/queue.mm610
-rw-r--r--intern/cycles/device/metal/util.h101
-rw-r--r--intern/cycles/device/metal/util.mm218
-rw-r--r--intern/cycles/device/multi/device.cpp43
-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.cpp526
-rw-r--r--intern/cycles/device/optix/device_impl.h17
-rw-r--r--intern/cycles/device/optix/queue.cpp13
-rw-r--r--intern/cycles/device/optix/queue.h4
-rw-r--r--intern/cycles/device/queue.cpp95
-rw-r--r--intern/cycles/device/queue.h186
-rw-r--r--intern/cycles/doc/license/readme.txt2
-rw-r--r--intern/cycles/graph/node.cpp8
-rw-r--r--intern/cycles/graph/node.h8
-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.txt8
-rw-r--r--intern/cycles/integrator/adaptive_sampling.cpp2
-rw-r--r--intern/cycles/integrator/denoiser.cpp27
-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.cpp32
-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.cpp31
-rw-r--r--intern/cycles/integrator/pass_accessor.h8
-rw-r--r--intern/cycles/integrator/pass_accessor_cpu.cpp145
-rw-r--r--intern/cycles/integrator/pass_accessor_cpu.h32
-rw-r--r--intern/cycles/integrator/pass_accessor_gpu.cpp49
-rw-r--r--intern/cycles/integrator/pass_accessor_gpu.h2
-rw-r--r--intern/cycles/integrator/path_trace.cpp189
-rw-r--r--intern/cycles/integrator/path_trace.h53
-rw-r--r--intern/cycles/integrator/path_trace_display.cpp261
-rw-r--r--intern/cycles/integrator/path_trace_display.h198
-rw-r--r--intern/cycles/integrator/path_trace_tile.cpp107
-rw-r--r--intern/cycles/integrator/path_trace_tile.h43
-rw-r--r--intern/cycles/integrator/path_trace_work.cpp27
-rw-r--r--intern/cycles/integrator/path_trace_work.h25
-rw-r--r--intern/cycles/integrator/path_trace_work_cpu.cpp65
-rw-r--r--intern/cycles/integrator/path_trace_work_cpu.h21
-rw-r--r--intern/cycles/integrator/path_trace_work_gpu.cpp567
-rw-r--r--intern/cycles/integrator/path_trace_work_gpu.h69
-rw-r--r--intern/cycles/integrator/render_scheduler.cpp52
-rw-r--r--intern/cycles/integrator/render_scheduler.h16
-rw-r--r--intern/cycles/integrator/shader_eval.cpp58
-rw-r--r--intern/cycles/integrator/shader_eval.h18
-rw-r--r--intern/cycles/integrator/tile.cpp35
-rw-r--r--intern/cycles/integrator/tile.h8
-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.cpp35
-rw-r--r--intern/cycles/integrator/work_tile_scheduler.h18
-rw-r--r--intern/cycles/kernel/CMakeLists.txt706
-rw-r--r--intern/cycles/kernel/bake/bake.h119
-rw-r--r--intern/cycles/kernel/bvh/bvh.h465
-rw-r--r--intern/cycles/kernel/bvh/bvh_embree.h147
-rw-r--r--intern/cycles/kernel/bvh/bvh_local.h211
-rw-r--r--intern/cycles/kernel/bvh/bvh_nodes.h153
-rw-r--r--intern/cycles/kernel/bvh/bvh_shadow_all.h296
-rw-r--r--intern/cycles/kernel/bvh/bvh_traversal.h239
-rw-r--r--intern/cycles/kernel/bvh/bvh_types.h44
-rw-r--r--intern/cycles/kernel/bvh/bvh_util.h186
-rw-r--r--intern/cycles/kernel/bvh/bvh_volume.h234
-rw-r--r--intern/cycles/kernel/bvh/bvh_volume_all.h303
-rw-r--r--intern/cycles/kernel/bvh/embree.h189
-rw-r--r--intern/cycles/kernel/bvh/local.h241
-rw-r--r--intern/cycles/kernel/bvh/metal.h50
-rw-r--r--intern/cycles/kernel/bvh/nodes.h153
-rw-r--r--intern/cycles/kernel/bvh/shadow_all.h360
-rw-r--r--intern/cycles/kernel/bvh/traversal.h271
-rw-r--r--intern/cycles/kernel/bvh/types.h45
-rw-r--r--intern/cycles/kernel/bvh/util.h219
-rw-r--r--intern/cycles/kernel/bvh/volume.h252
-rw-r--r--intern/cycles/kernel/bvh/volume_all.h319
-rw-r--r--intern/cycles/kernel/camera/camera.h521
-rw-r--r--intern/cycles/kernel/camera/projection.h315
-rw-r--r--intern/cycles/kernel/closure/alloc.h17
-rw-r--r--intern/cycles/kernel/closure/bsdf.h46
-rw-r--r--intern/cycles/kernel/closure/bsdf_ashikhmin_shirley.h43
-rw-r--r--intern/cycles/kernel/closure/bsdf_ashikhmin_velvet.h30
-rw-r--r--intern/cycles/kernel/closure/bsdf_diffuse.h56
-rw-r--r--intern/cycles/kernel/closure/bsdf_diffuse_ramp.h28
-rw-r--r--intern/cycles/kernel/closure/bsdf_hair.h54
-rw-r--r--intern/cycles/kernel/closure/bsdf_hair_principled.h64
-rw-r--r--intern/cycles/kernel/closure/bsdf_microfacet.h139
-rw-r--r--intern/cycles/kernel/closure/bsdf_microfacet_multi.h120
-rw-r--r--intern/cycles/kernel/closure/bsdf_microfacet_multi_impl.h22
-rw-r--r--intern/cycles/kernel/closure/bsdf_oren_nayar.h34
-rw-r--r--intern/cycles/kernel/closure/bsdf_phong_ramp.h30
-rw-r--r--intern/cycles/kernel/closure/bsdf_principled_diffuse.h117
-rw-r--r--intern/cycles/kernel/closure/bsdf_principled_sheen.h31
-rw-r--r--intern/cycles/kernel/closure/bsdf_reflection.h24
-rw-r--r--intern/cycles/kernel/closure/bsdf_refraction.h24
-rw-r--r--intern/cycles/kernel/closure/bsdf_toon.h62
-rw-r--r--intern/cycles/kernel/closure/bsdf_transparent.h28
-rw-r--r--intern/cycles/kernel/closure/bsdf_util.h120
-rw-r--r--intern/cycles/kernel/closure/bssrdf.h231
-rw-r--r--intern/cycles/kernel/closure/emissive.h11
-rw-r--r--intern/cycles/kernel/closure/volume.h59
-rw-r--r--intern/cycles/kernel/device/cpu/compat.h12
-rw-r--r--intern/cycles/kernel/device/cpu/globals.h13
-rw-r--r--intern/cycles/kernel/device/cpu/image.h8
-rw-r--r--intern/cycles/kernel/device/cpu/kernel.cpp6
-rw-r--r--intern/cycles/kernel/device/cpu/kernel.h19
-rw-r--r--intern/cycles/kernel/device/cpu/kernel_arch.h68
-rw-r--r--intern/cycles/kernel/device/cpu/kernel_arch_impl.h202
-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.h17
-rw-r--r--intern/cycles/kernel/device/cuda/config.h19
-rw-r--r--intern/cycles/kernel/device/cuda/globals.h12
-rw-r--r--intern/cycles/kernel/device/gpu/image.h16
-rw-r--r--intern/cycles/kernel/device/gpu/kernel.h946
-rw-r--r--intern/cycles/kernel/device/gpu/parallel_active_index.h116
-rw-r--r--intern/cycles/kernel/device/gpu/parallel_prefix_sum.h14
-rw-r--r--intern/cycles/kernel/device/gpu/parallel_sorted_index.h26
-rw-r--r--intern/cycles/kernel/device/gpu/work_stealing.h55
-rw-r--r--intern/cycles/kernel/device/hip/compat.h10
-rw-r--r--intern/cycles/kernel/device/hip/config.h19
-rw-r--r--intern/cycles/kernel/device/hip/globals.h13
-rw-r--r--intern/cycles/kernel/device/metal/compat.h316
-rw-r--r--intern/cycles/kernel/device/metal/context_begin.h83
-rw-r--r--intern/cycles/kernel/device/metal/context_end.h23
-rw-r--r--intern/cycles/kernel/device/metal/globals.h51
-rw-r--r--intern/cycles/kernel/device/metal/kernel.metal765
-rw-r--r--intern/cycles/kernel/device/optix/compat.h18
-rw-r--r--intern/cycles/kernel/device/optix/globals.h12
-rw-r--r--intern/cycles/kernel/device/optix/kernel.cu319
-rw-r--r--intern/cycles/kernel/device/optix/kernel_shader_raytrace.cu3
-rw-r--r--intern/cycles/kernel/film/accumulate.h592
-rw-r--r--intern/cycles/kernel/film/adaptive_sampling.h160
-rw-r--r--intern/cycles/kernel/film/id_passes.h106
-rw-r--r--intern/cycles/kernel/film/passes.h316
-rw-r--r--intern/cycles/kernel/film/read.h547
-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.h121
-rw-r--r--intern/cycles/kernel/geom/curve.h340
-rw-r--r--intern/cycles/kernel/geom/curve_intersect.h771
-rw-r--r--intern/cycles/kernel/geom/geom.h33
-rw-r--r--intern/cycles/kernel/geom/geom_attribute.h116
-rw-r--r--intern/cycles/kernel/geom/geom_curve.h328
-rw-r--r--intern/cycles/kernel/geom/geom_curve_intersect.h794
-rw-r--r--intern/cycles/kernel/geom/geom_motion_curve.h182
-rw-r--r--intern/cycles/kernel/geom/geom_motion_triangle.h186
-rw-r--r--intern/cycles/kernel/geom/geom_motion_triangle_intersect.h302
-rw-r--r--intern/cycles/kernel/geom/geom_motion_triangle_shader.h119
-rw-r--r--intern/cycles/kernel/geom/geom_object.h594
-rw-r--r--intern/cycles/kernel/geom/geom_patch.h460
-rw-r--r--intern/cycles/kernel/geom/geom_primitive.h347
-rw-r--r--intern/cycles/kernel/geom/geom_shader_data.h373
-rw-r--r--intern/cycles/kernel/geom/geom_subd_triangle.h689
-rw-r--r--intern/cycles/kernel/geom/geom_triangle.h370
-rw-r--r--intern/cycles/kernel/geom/geom_triangle_intersect.h309
-rw-r--r--intern/cycles/kernel/geom/geom_volume.h97
-rw-r--r--intern/cycles/kernel/geom/motion_curve.h155
-rw-r--r--intern/cycles/kernel/geom/motion_point.h74
-rw-r--r--intern/cycles/kernel/geom/motion_triangle.h201
-rw-r--r--intern/cycles/kernel/geom/motion_triangle_intersect.h176
-rw-r--r--intern/cycles/kernel/geom/motion_triangle_shader.h109
-rw-r--r--intern/cycles/kernel/geom/object.h600
-rw-r--r--intern/cycles/kernel/geom/patch.h470
-rw-r--r--intern/cycles/kernel/geom/point.h175
-rw-r--r--intern/cycles/kernel/geom/point_intersect.h128
-rw-r--r--intern/cycles/kernel/geom/primitive.h399
-rw-r--r--intern/cycles/kernel/geom/shader_data.h456
-rw-r--r--intern/cycles/kernel/geom/subd_triangle.h680
-rw-r--r--intern/cycles/kernel/geom/triangle.h370
-rw-r--r--intern/cycles/kernel/geom/triangle_intersect.h171
-rw-r--r--intern/cycles/kernel/geom/volume.h97
-rw-r--r--intern/cycles/kernel/integrator/init_from_bake.h205
-rw-r--r--intern/cycles/kernel/integrator/init_from_camera.h125
-rw-r--r--intern/cycles/kernel/integrator/integrator_init_from_bake.h182
-rw-r--r--intern/cycles/kernel/integrator/integrator_init_from_camera.h120
-rw-r--r--intern/cycles/kernel/integrator/integrator_intersect_closest.h248
-rw-r--r--intern/cycles/kernel/integrator/integrator_intersect_shadow.h144
-rw-r--r--intern/cycles/kernel/integrator/integrator_intersect_subsurface.h36
-rw-r--r--intern/cycles/kernel/integrator/integrator_intersect_volume_stack.h198
-rw-r--r--intern/cycles/kernel/integrator/integrator_megakernel.h93
-rw-r--r--intern/cycles/kernel/integrator/integrator_shade_background.h215
-rw-r--r--intern/cycles/kernel/integrator/integrator_shade_light.h126
-rw-r--r--intern/cycles/kernel/integrator/integrator_shade_shadow.h182
-rw-r--r--intern/cycles/kernel/integrator/integrator_shade_surface.h502
-rw-r--r--intern/cycles/kernel/integrator/integrator_shade_volume.h1019
-rw-r--r--intern/cycles/kernel/integrator/integrator_state.h185
-rw-r--r--intern/cycles/kernel/integrator/integrator_state_flow.h144
-rw-r--r--intern/cycles/kernel/integrator/integrator_state_template.h163
-rw-r--r--intern/cycles/kernel/integrator/integrator_state_util.h273
-rw-r--r--intern/cycles/kernel/integrator/integrator_subsurface.h623
-rw-r--r--intern/cycles/kernel/integrator/integrator_volume_stack.h223
-rw-r--r--intern/cycles/kernel/integrator/intersect_closest.h363
-rw-r--r--intern/cycles/kernel/integrator/intersect_shadow.h193
-rw-r--r--intern/cycles/kernel/integrator/intersect_subsurface.h36
-rw-r--r--intern/cycles/kernel/integrator/intersect_volume_stack.h239
-rw-r--r--intern/cycles/kernel/integrator/megakernel.h113
-rw-r--r--intern/cycles/kernel/integrator/path_state.h378
-rw-r--r--intern/cycles/kernel/integrator/shade_background.h205
-rw-r--r--intern/cycles/kernel/integrator/shade_light.h129
-rw-r--r--intern/cycles/kernel/integrator/shade_shadow.h192
-rw-r--r--intern/cycles/kernel/integrator/shade_surface.h568
-rw-r--r--intern/cycles/kernel/integrator/shade_volume.h1049
-rw-r--r--intern/cycles/kernel/integrator/shader_eval.h901
-rw-r--r--intern/cycles/kernel/integrator/shadow_catcher.h116
-rw-r--r--intern/cycles/kernel/integrator/shadow_state_template.h88
-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.h112
-rw-r--r--intern/cycles/kernel/integrator/state_util.h440
-rw-r--r--intern/cycles/kernel/integrator/subsurface.h203
-rw-r--r--intern/cycles/kernel/integrator/subsurface_disk.h214
-rw-r--r--intern/cycles/kernel/integrator/subsurface_random_walk.h475
-rw-r--r--intern/cycles/kernel/integrator/volume_stack.h225
-rw-r--r--intern/cycles/kernel/kernel_accumulate.h514
-rw-r--r--intern/cycles/kernel/kernel_adaptive_sampling.h159
-rw-r--r--intern/cycles/kernel/kernel_bake.h94
-rw-r--r--intern/cycles/kernel/kernel_camera.h519
-rw-r--r--intern/cycles/kernel/kernel_color.h35
-rw-r--r--intern/cycles/kernel/kernel_differential.h166
-rw-r--r--intern/cycles/kernel/kernel_emission.h266
-rw-r--r--intern/cycles/kernel/kernel_film.h529
-rw-r--r--intern/cycles/kernel/kernel_id_passes.h106
-rw-r--r--intern/cycles/kernel/kernel_jitter.h165
-rw-r--r--intern/cycles/kernel/kernel_light.h877
-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.h301
-rw-r--r--intern/cycles/kernel/kernel_passes.h325
-rw-r--r--intern/cycles/kernel/kernel_path_state.h367
-rw-r--r--intern/cycles/kernel/kernel_profiling.h40
-rw-r--r--intern/cycles/kernel/kernel_projection.h258
-rw-r--r--intern/cycles/kernel/kernel_random.h219
-rw-r--r--intern/cycles/kernel/kernel_shader.h863
-rw-r--r--intern/cycles/kernel/kernel_shadow_catcher.h116
-rw-r--r--intern/cycles/kernel/kernel_textures.h89
-rw-r--r--intern/cycles/kernel/kernel_types.h1547
-rw-r--r--intern/cycles/kernel/kernel_work_stealing.h52
-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.h924
-rw-r--r--intern/cycles/kernel/light/sample.h322
-rw-r--r--intern/cycles/kernel/osl/CMakeLists.txt20
-rw-r--r--intern/cycles/kernel/osl/background.cpp6
-rw-r--r--intern/cycles/kernel/osl/bsdf_diffuse_ramp.cpp7
-rw-r--r--intern/cycles/kernel/osl/bsdf_phong_ramp.cpp6
-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.cpp6
-rw-r--r--intern/cycles/kernel/osl/globals.h109
-rw-r--r--intern/cycles/kernel/osl/osl_bssrdf.cpp119
-rw-r--r--intern/cycles/kernel/osl/osl_closures.cpp1008
-rw-r--r--intern/cycles/kernel/osl/osl_closures.h161
-rw-r--r--intern/cycles/kernel/osl/osl_globals.h109
-rw-r--r--intern/cycles/kernel/osl/osl_services.cpp1693
-rw-r--r--intern/cycles/kernel/osl/osl_services.h329
-rw-r--r--intern/cycles/kernel/osl/osl_shader.cpp428
-rw-r--r--intern/cycles/kernel/osl/osl_shader.h84
-rw-r--r--intern/cycles/kernel/osl/services.cpp1757
-rw-r--r--intern/cycles/kernel/osl/services.h334
-rw-r--r--intern/cycles/kernel/osl/shader.cpp430
-rw-r--r--intern/cycles/kernel/osl/shader.h82
-rw-r--r--intern/cycles/kernel/osl/shaders/CMakeLists.txt157
-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.osl32
-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.osl270
-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.osl111
-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.osl803
-rw-r--r--intern/cycles/kernel/osl/shaders/node_noise.h202
-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.osl88
-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_point_info.osl26
-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_map_range.osl74
-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.h53
-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.h174
-rw-r--r--intern/cycles/kernel/shaders/CMakeLists.txt154
-rw-r--r--intern/cycles/kernel/shaders/node_image_texture.osl270
-rw-r--r--intern/cycles/kernel/shaders/node_magic_texture.osl108
-rw-r--r--intern/cycles/kernel/shaders/node_musgrave_texture.osl803
-rw-r--r--intern/cycles/kernel/shaders/node_noise.h202
-rw-r--r--intern/cycles/kernel/shaders/node_normal_map.osl90
-rw-r--r--intern/cycles/kernel/svm/ao.h145
-rw-r--r--intern/cycles/kernel/svm/aov.h71
-rw-r--r--intern/cycles/kernel/svm/attribute.h352
-rw-r--r--intern/cycles/kernel/svm/bevel.h340
-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.h278
-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.h131
-rw-r--r--intern/cycles/kernel/svm/map_range.h165
-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.h258
-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.h243
-rw-r--r--intern/cycles/kernel/svm/svm_ao.h132
-rw-r--r--intern/cycles/kernel/svm/svm_aov.h63
-rw-r--r--intern/cycles/kernel/svm/svm_attribute.h343
-rw-r--r--intern/cycles/kernel/svm/svm_bevel.h318
-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.h1199
-rw-r--r--intern/cycles/kernel/svm/svm_color_util.h321
-rw-r--r--intern/cycles/kernel/svm/svm_convert.h72
-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.h77
-rw-r--r--intern/cycles/kernel/svm/svm_gamma.h31
-rw-r--r--intern/cycles/kernel/svm/svm_geometry.h241
-rw-r--r--intern/cycles/kernel/svm/svm_gradient.h80
-rw-r--r--intern/cycles/kernel/svm/svm_hsv.h64
-rw-r--r--intern/cycles/kernel/svm/svm_ies.h123
-rw-r--r--intern/cycles/kernel/svm/svm_image.h251
-rw-r--r--intern/cycles/kernel/svm/svm_invert.h38
-rw-r--r--intern/cycles/kernel/svm/svm_light_path.h142
-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.h110
-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.h45
-rw-r--r--intern/cycles/kernel/svm/svm_sky.h333
-rw-r--r--intern/cycles/kernel/svm/svm_tex_coord.h414
-rw-r--r--intern/cycles/kernel/svm/svm_types.h606
-rw-r--r--intern/cycles/kernel/svm/svm_value.h39
-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.h1145
-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.h98
-rw-r--r--intern/cycles/kernel/svm/svm_white_noise.h80
-rw-r--r--intern/cycles/kernel/svm/svm_wireframe.h122
-rw-r--r--intern/cycles/kernel/svm/tex_coord.h426
-rw-r--r--intern/cycles/kernel/svm/types.h607
-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.h68
-rw-r--r--intern/cycles/kernel/svm/white_noise.h82
-rw-r--r--intern/cycles/kernel/svm/wireframe.h129
-rw-r--r--intern/cycles/kernel/tables.h76
-rw-r--r--intern/cycles/kernel/textures.h95
-rw-r--r--intern/cycles/kernel/types.h1660
-rw-r--r--intern/cycles/kernel/util/color.h35
-rw-r--r--intern/cycles/kernel/util/differential.h166
-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.cpp891
-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.cpp361
-rw-r--r--intern/cycles/render/buffers.h190
-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/denoising.h216
-rw-r--r--intern/cycles/render/film.cpp691
-rw-r--r--intern/cycles/render/film.h100
-rw-r--r--intern/cycles/render/geometry.cpp2181
-rw-r--r--intern/cycles/render/geometry.h298
-rw-r--r--intern/cycles/render/gpu_display.cpp227
-rw-r--r--intern/cycles/render/gpu_display.h247
-rw-r--r--intern/cycles/render/graph.cpp1237
-rw-r--r--intern/cycles/render/graph.h385
-rw-r--r--intern/cycles/render/hair.cpp542
-rw-r--r--intern/cycles/render/hair.h157
-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.cpp1148
-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.cpp857
-rw-r--r--intern/cycles/render/mesh.h267
-rw-r--r--intern/cycles/render/mesh_displace.cpp409
-rw-r--r--intern/cycles/render/mesh_subdivision.cpp648
-rw-r--r--intern/cycles/render/nodes.cpp7091
-rw-r--r--intern/cycles/render/nodes.h1557
-rw-r--r--intern/cycles/render/object.cpp977
-rw-r--r--intern/cycles/render/object.h186
-rw-r--r--intern/cycles/render/osl.cpp1304
-rw-r--r--intern/cycles/render/osl.h198
-rw-r--r--intern/cycles/render/particles.cpp149
-rw-r--r--intern/cycles/render/particles.h80
-rw-r--r--intern/cycles/render/pass.cpp427
-rw-r--r--intern/cycles/render/pass.h106
-rw-r--r--intern/cycles/render/procedural.cpp89
-rw-r--r--intern/cycles/render/scene.cpp912
-rw-r--r--intern/cycles/render/scene.h409
-rw-r--r--intern/cycles/render/session.cpp743
-rw-r--r--intern/cycles/render/session.h251
-rw-r--r--intern/cycles/render/shader.cpp876
-rw-r--r--intern/cycles/render/shader.h259
-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.cpp984
-rw-r--r--intern/cycles/render/svm.h238
-rw-r--r--intern/cycles/render/tables.cpp130
-rw-r--r--intern/cycles/render/tables.h57
-rw-r--r--intern/cycles/render/tile.cpp591
-rw-r--r--intern/cycles/render/tile.h170
-rw-r--r--intern/cycles/render/volume.cpp635
-rw-r--r--intern/cycles/render/volume.h38
-rw-r--r--intern/cycles/scene/CMakeLists.txt165
-rw-r--r--intern/cycles/scene/alembic.cpp1535
-rw-r--r--intern/cycles/scene/alembic.h584
-rw-r--r--intern/cycles/scene/alembic_read.cpp1120
-rw-r--r--intern/cycles/scene/alembic_read.h155
-rw-r--r--intern/cycles/scene/attribute.cpp933
-rw-r--r--intern/cycles/scene/attribute.h282
-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.cpp828
-rw-r--r--intern/cycles/scene/camera.h242
-rw-r--r--intern/cycles/scene/colorspace.cpp459
-rw-r--r--intern/cycles/scene/colorspace.h64
-rw-r--r--intern/cycles/scene/constant_fold.cpp455
-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.cpp690
-rw-r--r--intern/cycles/scene/film.h100
-rw-r--r--intern/cycles/scene/geometry.cpp2222
-rw-r--r--intern/cycles/scene/geometry.h282
-rw-r--r--intern/cycles/scene/hair.cpp632
-rw-r--r--intern/cycles/scene/hair.h164
-rw-r--r--intern/cycles/scene/image.cpp913
-rw-r--r--intern/cycles/scene/image.h248
-rw-r--r--intern/cycles/scene/image_oiio.cpp239
-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.cpp401
-rw-r--r--intern/cycles/scene/integrator.h125
-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.cpp829
-rw-r--r--intern/cycles/scene/mesh.h266
-rw-r--r--intern/cycles/scene/mesh_displace.cpp410
-rw-r--r--intern/cycles/scene/mesh_subdivision.cpp679
-rw-r--r--intern/cycles/scene/object.cpp1018
-rw-r--r--intern/cycles/scene/object.h190
-rw-r--r--intern/cycles/scene/osl.cpp1316
-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.cpp432
-rw-r--r--intern/cycles/scene/pass.h106
-rw-r--r--intern/cycles/scene/pointcloud.cpp304
-rw-r--r--intern/cycles/scene/pointcloud.h114
-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.cpp990
-rw-r--r--intern/cycles/scene/scene.h426
-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.cpp7303
-rw-r--r--intern/cycles/scene/shader_nodes.h1595
-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.cpp665
-rw-r--r--intern/cycles/session/denoising.h184
-rw-r--r--intern/cycles/session/display_driver.h147
-rw-r--r--intern/cycles/session/merge.cpp621
-rw-r--r--intern/cycles/session/merge.h43
-rw-r--r--intern/cycles/session/output_driver.h82
-rw-r--r--intern/cycles/session/session.cpp645
-rw-r--r--intern/cycles/session/session.h234
-rw-r--r--intern/cycles/session/tile.cpp674
-rw-r--r--intern/cycles/session/tile.h192
-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.txt39
-rw-r--r--intern/cycles/test/integrator_adaptive_sampling_test.cpp2
-rw-r--r--intern/cycles/test/integrator_tile_test.cpp22
-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.h45
-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.txt250
-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.h322
-rw-r--r--intern/cycles/util/atomic.h124
-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.cpp114
-rw-r--r--intern/cycles/util/debug.h179
-rw-r--r--intern/cycles/util/defines.h153
-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.h195
-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.h934
-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.h652
-rw-r--r--intern/cycles/util/math_float2.h274
-rw-r--r--intern/cycles/util/math_float3.h574
-rw-r--r--intern/cycles/util/math_float4.h541
-rw-r--r--intern/cycles/util/math_int2.h77
-rw-r--r--intern/cycles/util/math_int3.h114
-rw-r--r--intern/cycles/util/math_int4.h153
-rw-r--r--intern/cycles/util/math_intersect.h232
-rw-r--r--intern/cycles/util/math_matrix.h454
-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.cpp931
-rw-r--r--intern/cycles/util/path.h76
-rw-r--r--intern/cycles/util/profiling.cpp179
-rw-r--r--intern/cycles/util/profiling.h182
-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.cpp329
-rw-r--r--intern/cycles/util/system.h46
-rw-r--r--intern/cycles/util/task.cpp252
-rw-r--r--intern/cycles/util/task.h147
-rw-r--r--intern/cycles/util/tbb.h55
-rw-r--r--intern/cycles/util/texture.h99
-rw-r--r--intern/cycles/util/thread.cpp69
-rw-r--r--intern/cycles/util/thread.h87
-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.h527
-rw-r--r--intern/cycles/util/types.h140
-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.h95
-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_atomic.h68
-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.h179
-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.h836
-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_fast.h652
-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_math_intersect.h249
-rw-r--r--intern/cycles/util/util_math_matrix.h448
-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.h216
-rw-r--r--intern/cycles/util/util_rect.h72
-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.h510
-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
1097 files changed, 152379 insertions, 139036 deletions
diff --git a/intern/cycles/CMakeLists.txt b/intern/cycles/CMakeLists.txt
index 2018c1d9648..8854170c642 100644
--- a/intern/cycles/CMakeLists.txt
+++ b/intern/cycles/CMakeLists.txt
@@ -226,6 +226,9 @@ add_definitions(
-DCCL_NAMESPACE_END=}
)
+if(WITH_CYCLES_DEBUG)
+ add_definitions(-DWITH_CYCLES_DEBUG)
+endif()
if(WITH_CYCLES_STANDALONE_GUI)
add_definitions(-DWITH_CYCLES_STANDALONE_GUI)
endif()
@@ -295,13 +298,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)
@@ -341,7 +337,7 @@ else()
endif()
# Warnings
-if(CMAKE_COMPILER_IS_GNUCXX)
+if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_C_COMPILER_ID MATCHES "Clang")
ADD_CHECK_CXX_COMPILER_FLAG(CMAKE_CXX_FLAGS _has_cxxflag_float_conversion "-Werror=float-conversion")
ADD_CHECK_CXX_COMPILER_FLAG(CMAKE_CXX_FLAGS _has_cxxflag_double_promotion "-Werror=double-promotion")
ADD_CHECK_CXX_COMPILER_FLAG(CMAKE_CXX_FLAGS _has_no_error_unused_macros "-Wno-error=unused-macros")
@@ -400,7 +396,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 f9dc5f00802..781639986f6 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
@@ -50,8 +51,6 @@ list(APPEND LIBRARIES ${CYCLES_GL_LIBRARIES})
# Common configuration.
-cycles_link_directories()
-
add_definitions(${GL_DEFINITIONS})
include_directories(${INC})
@@ -64,6 +63,8 @@ if(WITH_CYCLES_STANDALONE)
cycles_standalone.cpp
cycles_xml.cpp
cycles_xml.h
+ oiio_output_driver.cpp
+ oiio_output_driver.h
)
add_executable(cycles ${SRC} ${INC} ${INC_SYS})
unset(SRC)
@@ -73,7 +74,7 @@ if(WITH_CYCLES_STANDALONE)
if(APPLE)
if(WITH_OPENCOLORIO)
- set_property(TARGET cycles APPEND_STRING PROPERTY LINK_FLAGS " -framework IOKit")
+ set_property(TARGET cycles APPEND_STRING PROPERTY LINK_FLAGS " -framework IOKit -framework Carbon")
endif()
if(WITH_OPENIMAGEDENOISE AND "${CMAKE_OSX_ARCHITECTURES}" STREQUAL "arm64")
# OpenImageDenoise uses BNNS from the Accelerate framework.
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 258e67b3459..7123edbef64 100644
--- a/intern/cycles/app/cycles_standalone.cpp
+++ b/intern/cycles/app/cycles_standalone.cpp
@@ -17,27 +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"
@@ -54,6 +57,7 @@ struct Options {
bool quiet;
bool show_help, interactive, pause;
string output_filepath;
+ string output_pass;
} options;
static void session_print(const string &str)
@@ -78,7 +82,7 @@ static void session_print_status()
string status, substatus;
/* get status */
- float progress = options.session->progress.get_progress();
+ double progress = options.session->progress.get_progress();
options.session->progress.get_status(status, substatus);
if (substatus != "")
@@ -89,30 +93,6 @@ static void session_print_status()
session_print(status);
}
-static bool write_render(const uchar *pixels, int w, int h, int channels)
-{
- string msg = string_printf("Writing image %s", options.output_path.c_str());
- session_print(msg);
-
- unique_ptr<ImageOutput> out = unique_ptr<ImageOutput>(ImageOutput::create(options.output_path));
- if (!out) {
- return false;
- }
-
- ImageSpec spec(w, h, channels, TypeDesc::UINT8);
- if (!out->open(options.output_path, spec)) {
- return false;
- }
-
- /* conversion for different top/bottom convention */
- out->write_image(
- TypeDesc::UINT8, pixels + (h - 1) * w * channels, AutoStride, -w * channels, AutoStride);
-
- out->close();
-
- return true;
-}
-
static BufferParams &session_buffer_params()
{
static BufferParams buffer_params;
@@ -147,9 +127,14 @@ static void scene_init()
static void session_init()
{
- options.session_params.write_render_cb = write_render;
+ options.output_pass = "combined";
options.session = new Session(options.session_params, options.scene_params);
+ if (!options.output_filepath.empty()) {
+ options.session->set_output_driver(make_unique<OIIOOutputDriver>(
+ options.output_filepath, options.output_pass, session_print));
+ }
+
if (options.session_params.background && !options.quiet)
options.session->progress.set_update_callback(function_bind(&session_print_status));
#ifdef WITH_CYCLES_STANDALONE_GUI
@@ -160,6 +145,11 @@ static void session_init()
/* load scene */
scene_init();
+ /* add pass for output. */
+ Pass *pass = options.scene->create_node<Pass>();
+ pass->set_name(ustring(options.output_pass.c_str()));
+ pass->set_type(PASS_COMBINED);
+
options.session->reset(options.session_params, session_buffer_params());
options.session->start();
}
@@ -193,7 +183,7 @@ static void display_info(Progress &progress)
progress.get_time(total_time, sample_time);
progress.get_status(status, substatus);
- float progress_val = progress.get_progress();
+ double progress_val = progress.get_progress();
if (substatus != "")
status += ": " + substatus;
diff --git a/intern/cycles/app/cycles_xml.cpp b/intern/cycles/app/cycles_xml.cpp
index 54f97fddbd9..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"
@@ -333,6 +333,7 @@ static void xml_read_shader_graph(XMLReadState &state, Shader *shader, xml_node
}
snode = (ShaderNode *)node_type->create(node_type);
+ snode->set_owner(graph);
}
xml_read_node(graph_reader, snode, node);
diff --git a/intern/cycles/app/oiio_output_driver.cpp b/intern/cycles/app/oiio_output_driver.cpp
new file mode 100644
index 00000000000..d791c89772f
--- /dev/null
+++ b/intern/cycles/app/oiio_output_driver.cpp
@@ -0,0 +1,71 @@
+/*
+ * 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 "app/oiio_output_driver.h"
+
+CCL_NAMESPACE_BEGIN
+
+OIIOOutputDriver::OIIOOutputDriver(const string_view filepath,
+ const string_view pass,
+ LogFunction log)
+ : filepath_(filepath), pass_(pass), log_(log)
+{
+}
+
+OIIOOutputDriver::~OIIOOutputDriver()
+{
+}
+
+void OIIOOutputDriver::write_render_tile(const Tile &tile)
+{
+ /* Only write the full buffer, no intermediate tiles. */
+ if (!(tile.size == tile.full_size)) {
+ return;
+ }
+
+ log_(string_printf("Writing image %s", filepath_.c_str()));
+
+ unique_ptr<ImageOutput> image_output(ImageOutput::create(filepath_));
+ if (image_output == nullptr) {
+ log_("Failed to create image file");
+ return;
+ }
+
+ const int width = tile.size.x;
+ const int height = tile.size.y;
+
+ ImageSpec spec(width, height, 4, TypeDesc::FLOAT);
+ if (!image_output->open(filepath_, spec)) {
+ log_("Failed to create image file");
+ return;
+ }
+
+ vector<float> pixels(width * height * 4);
+ if (!tile.get_pass_pixels(pass_, 4, pixels.data())) {
+ log_("Failed to read render pass pixels");
+ return;
+ }
+
+ /* Manipulate offset and stride to convert from bottom-up to top-down convention. */
+ image_output->write_image(TypeDesc::FLOAT,
+ pixels.data() + (height - 1) * width * 4,
+ AutoStride,
+ -width * 4 * sizeof(float),
+ AutoStride);
+ image_output->close();
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/app/oiio_output_driver.h b/intern/cycles/app/oiio_output_driver.h
new file mode 100644
index 00000000000..a5c88e0e890
--- /dev/null
+++ b/intern/cycles/app/oiio_output_driver.h
@@ -0,0 +1,42 @@
+/*
+ * 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 "session/output_driver.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
+
+class OIIOOutputDriver : public OutputDriver {
+ public:
+ typedef function<void(const string &)> LogFunction;
+
+ OIIOOutputDriver(const string_view filepath, const string_view pass, LogFunction log);
+ virtual ~OIIOOutputDriver();
+
+ void write_render_tile(const Tile &tile) override;
+
+ protected:
+ string filepath_;
+ string pass_;
+ LogFunction log_;
+};
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/CMakeLists.txt b/intern/cycles/blender/CMakeLists.txt
index 64d226cb9ec..fe7d0b89bb0 100644
--- a/intern/cycles/blender/CMakeLists.txt
+++ b/intern/cycles/blender/CMakeLists.txt
@@ -29,37 +29,40 @@ set(INC_SYS
)
set(SRC
- blender_camera.cpp
- blender_device.cpp
- blender_image.cpp
- blender_geometry.cpp
- blender_gpu_display.cpp
- blender_light.cpp
- blender_mesh.cpp
- blender_object.cpp
- blender_object_cull.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
+ pointcloud.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_gpu_display.h
- blender_id_map.h
- blender_image.h
- blender_object_cull.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
@@ -67,7 +70,8 @@ set(LIB
cycles_device
cycles_graph
cycles_kernel
- cycles_render
+ cycles_scene
+ cycles_session
cycles_subd
cycles_util
@@ -84,6 +88,7 @@ endif()
set(ADDON_FILES
addon/__init__.py
+ addon/camera.py
addon/engine.py
addon/operators.py
addon/osl.py
@@ -98,6 +103,11 @@ add_definitions(${GL_DEFINITIONS})
if(WITH_CYCLES_DEVICE_HIP)
add_definitions(-DWITH_HIP)
endif()
+
+if(WITH_CYCLES_DEVICE_METAL)
+ add_definitions(-DWITH_METAL)
+endif()
+
if(WITH_MOD_FLUID)
add_definitions(-DWITH_FLUID)
endif()
@@ -135,11 +145,6 @@ endif()
blender_add_lib(bf_intern_cycles "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
-# avoid link failure with clang 3.4 debug
-if(CMAKE_C_COMPILER_ID MATCHES "Clang" AND NOT ${CMAKE_C_COMPILER_VERSION} VERSION_LESS '3.4')
- string(APPEND CMAKE_CXX_FLAGS_DEBUG " -gline-tables-only")
-endif()
-
add_dependencies(bf_intern_cycles bf_rna)
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${ADDON_FILES}" ${CYCLES_INSTALL_PATH})
diff --git a/intern/cycles/blender/addon/camera.py b/intern/cycles/blender/addon/camera.py
new file mode 100644
index 00000000000..d4133796875
--- /dev/null
+++ b/intern/cycles/blender/addon/camera.py
@@ -0,0 +1,84 @@
+#
+# 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.
+#
+
+# <pep8 compliant>
+
+# Fit to match default projective camera with focal_length 50 and sensor_width 36.
+default_fisheye_polynomial = [-1.1735143712967577e-05,
+ -0.019988736953434998,
+ -3.3525322965709175e-06,
+ 3.099275275886036e-06,
+ -2.6064646454854524e-08]
+
+# Utilities to generate lens polynomials to match built-in camera types, only here
+# for reference at the moment, not used by the code.
+def create_grid(sensor_height, sensor_width):
+ import numpy as np
+ if sensor_height is None:
+ sensor_height = sensor_width / (16 / 9) # Default aspect ration 16:9
+ uu, vv = np.meshgrid(np.linspace(0, 1, 100), np.linspace(0, 1, 100))
+ uu = (uu - 0.5) * sensor_width
+ vv = (vv - 0.5) * sensor_height
+ rr = np.sqrt(uu ** 2 + vv ** 2)
+ return rr
+
+
+def fisheye_lens_polynomial_from_projective(focal_length=50, sensor_width=36, sensor_height=None):
+ import numpy as np
+ rr = create_grid(sensor_height, sensor_width)
+ polynomial = np.polyfit(rr.flat, (-np.arctan(rr / focal_length)).flat, 4)
+ return list(reversed(polynomial))
+
+
+def fisheye_lens_polynomial_from_projective_fov(fov, sensor_width=36, sensor_height=None):
+ import numpy as np
+ f = sensor_width / 2 / np.tan(fov / 2)
+ return fisheye_lens_polynomial_from_projective(f, sensor_width, sensor_height)
+
+
+def fisheye_lens_polynomial_from_equisolid(lens=10.5, sensor_width=36, sensor_height=None):
+ import numpy as np
+ rr = create_grid(sensor_height, sensor_width)
+ x = rr.reshape(-1)
+ x = np.stack([x**i for i in [1, 2, 3, 4]])
+ y = (-2 * np.arcsin(rr / (2 * lens))).reshape(-1)
+ polynomial = np.linalg.lstsq(x.T, y.T, rcond=None)[0]
+ return [0] + list(polynomial)
+
+
+def fisheye_lens_polynomial_from_equidistant(fov=180, sensor_width=36, sensor_height=None):
+ import numpy as np
+ return [0, -np.radians(fov) / sensor_width, 0, 0, 0]
+
+
+def fisheye_lens_polynomial_from_distorted_projective_polynomial(k1, k2, k3, focal_length=50, sensor_width=36, sensor_height=None):
+ import numpy as np
+ rr = create_grid(sensor_height, sensor_width)
+ r2 = (rr / focal_length) ** 2
+ r4 = r2 * r2
+ r6 = r4 * r2
+ r_coeff = 1 + k1 * r2 + k2 * r4 + k3 * r6
+ polynomial = np.polyfit(rr.flat, (-np.arctan(rr / focal_length * r_coeff)).flat, 4)
+ return list(reversed(polynomial))
+
+def fisheye_lens_polynomial_from_distorted_projective_divisions(k1, k2, focal_length=50, sensor_width=36, sensor_height=None):
+ import numpy as np
+ rr = create_grid(sensor_height, sensor_width)
+ r2 = (rr / focal_length) ** 2
+ r4 = r2 * r2
+ r_coeff = 1 + k1 * r2 + k2 * r4
+ polynomial = np.polyfit(rr.flat, (-np.arctan(rr / focal_length / r_coeff)).flat, 4)
+ return list(reversed(polynomial))
diff --git a/intern/cycles/blender/addon/engine.py b/intern/cycles/blender/addon/engine.py
index d729cb1ee69..88526212d31 100644
--- a/intern/cycles/blender/addon/engine.py
+++ b/intern/cycles/blender/addon/engine.py
@@ -28,7 +28,7 @@ def _configure_argument_parser():
action='store_true')
parser.add_argument("--cycles-device",
help="Set the device to use for Cycles, overriding user preferences and the scene setting."
- "Valid options are 'CPU', 'CUDA', 'OPTIX', or 'HIP'"
+ "Valid options are 'CPU', 'CUDA', 'OPTIX', 'HIP' or 'METAL'."
"Additionally, you can append '+CPU' to any GPU type for hybrid rendering.",
default=None)
return parser
@@ -60,9 +60,8 @@ def init():
path = os.path.dirname(__file__)
user_path = os.path.dirname(os.path.abspath(bpy.utils.user_resource('CONFIG', path='')))
- temp_path = bpy.app.tempdir
- _cycles.init(path, user_path, temp_path, bpy.app.background)
+ _cycles.init(path, user_path, bpy.app.background)
_parse_command_line()
@@ -211,7 +210,6 @@ def list_render_passes(scene, srl):
if crl.use_pass_shadow_catcher: yield ("Shadow Catcher", "RGB", 'COLOR')
# Debug passes.
- if crl.pass_debug_render_time: yield ("Debug Render Time", "X", 'VALUE')
if crl.pass_debug_sample_count: yield ("Debug Sample Count", "X", 'VALUE')
# Cryptomatte passes.
@@ -234,6 +232,7 @@ def list_render_passes(scene, srl):
if crl.denoising_store_passes:
yield ("Denoising Normal", "XYZ", 'VECTOR')
yield ("Denoising Albedo", "RGB", 'COLOR')
+ yield ("Denoising Depth", "Z", 'VALUE')
# Custom AOV passes.
for aov in srl.aovs:
diff --git a/intern/cycles/blender/addon/presets.py b/intern/cycles/blender/addon/presets.py
index 37c39904e30..50093438bda 100644
--- a/intern/cycles/blender/addon/presets.py
+++ b/intern/cycles/blender/addon/presets.py
@@ -40,10 +40,10 @@ class AddPresetIntegrator(AddPresetBase, Operator):
"cycles.transparent_max_bounces",
"cycles.caustics_reflective",
"cycles.caustics_refractive",
- "cycles.blur_glossy"
- "cycles.use_fast_gi"
- "cycles.ao_bounces"
- "cycles.ao_bounces_render"
+ "cycles.blur_glossy",
+ "cycles.use_fast_gi",
+ "cycles.ao_bounces",
+ "cycles.ao_bounces_render",
]
preset_subdir = "cycles/integrator"
diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py
index cea70033784..6e498f92854 100644
--- a/intern/cycles/blender/addon/properties.py
+++ b/intern/cycles/blender/addon/properties.py
@@ -33,6 +33,7 @@ from math import pi
# enums
from . import engine
+from . import camera
enum_devices = (
('CPU', "CPU", "Use CPU for rendering"),
@@ -72,6 +73,8 @@ enum_panorama_types = (
('FISHEYE_EQUISOLID', "Fisheye Equisolid",
"Similar to most fisheye modern lens, takes sensor dimensions into consideration"),
('MIRRORBALL', "Mirror Ball", "Uses the mirror ball mapping"),
+ ('FISHEYE_LENS_POLYNOMIAL', "Fisheye Lens Polynomial",
+ "Defines the lens projection as polynomial to allow real world camera lenses to be mimicked."),
)
enum_curve_shape = (
@@ -86,8 +89,8 @@ enum_use_layer_samples = (
)
enum_sampling_pattern = (
- ('SOBOL', "Sobol", "Use Sobol random sampling pattern"),
- ('PROGRESSIVE_MUTI_JITTER', "Progressive Multi-Jitter", "Use Progressive Multi-Jitter random sampling pattern"),
+ ('SOBOL', "Sobol", "Use Sobol random sampling pattern", 0),
+ ('PROGRESSIVE_MULTI_JITTER', "Progressive Multi-Jitter", "Use Progressive Multi-Jitter random sampling pattern", 1),
)
enum_volume_sampling = (
@@ -111,7 +114,8 @@ enum_device_type = (
('CPU', "CPU", "CPU", 0),
('CUDA', "CUDA", "CUDA", 1),
('OPTIX', "OptiX", "OptiX", 3),
- ("HIP", "HIP", "HIP", 4)
+ ('HIP', "HIP", "HIP", 4),
+ ('METAL', "Metal", "Metal", 5)
)
enum_texture_limit = (
@@ -125,6 +129,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", ""),
@@ -213,6 +222,12 @@ enum_denoising_prefilter = (
('ACCURATE', "Accurate", "Prefilter noisy guiding passes before denoising color. Improves quality when guiding passes are noisy using extra processing time", 3),
)
+enum_direct_light_sampling_type = (
+ ('MULTIPLE_IMPORTANCE_SAMPLING', "Multiple Importance Sampling", "Multiple importance sampling is used to combine direct light contributions from next-event estimation and forward path tracing", 0),
+ ('FORWARD_PATH_TRACING', "Forward Path Tracing", "Direct light contributions are only sampled using forward path tracing", 1),
+ ('NEXT_EVENT_ESTIMATION', "Next-Event Estimation", "Direct light contributions are only sampled using next-event estimation", 2),
+)
+
def update_render_passes(self, context):
scene = context.scene
view_layer = context.view_layer
@@ -320,6 +335,13 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
default=1024,
)
+ sample_offset: IntProperty(
+ name="Sample Offset",
+ description="Number of samples to skip when starting render",
+ min=0, max=(1 << 24),
+ default=0,
+ )
+
time_limit: FloatProperty(
name="Time Limit",
description="Limit the render time (excluding synchronization time)."
@@ -332,9 +354,27 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
sampling_pattern: EnumProperty(
name="Sampling Pattern",
- description="Random sampling pattern used by the integrator",
+ description="Random sampling pattern used by the integrator. When adaptive sampling is enabled, Progressive Multi-Jitter is always used instead of Sobol",
items=enum_sampling_pattern,
- default='PROGRESSIVE_MUTI_JITTER',
+ default='PROGRESSIVE_MULTI_JITTER',
+ )
+
+ scrambling_distance: FloatProperty(
+ name="Scrambling Distance",
+ default=1.0,
+ min=0.0, max=1.0,
+ description="Reduce randomization between pixels to improve GPU rendering performance, at the cost of possible rendering 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",
+ )
+
+ auto_scrambling_distance: BoolProperty(
+ name="Automatic Scrambling Distance",
+ default=False,
+ description="Automatically reduce the randomization between pixels to improve GPU rendering performance, at the cost of possible rendering artifacts. Only works when not using adaptive sampling",
)
use_layer_samples: EnumProperty(
@@ -392,6 +432,13 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
default=0,
)
+ direct_light_sampling_type: EnumProperty(
+ name="Direct Light Sampling",
+ description="The type of strategy used for sampling direct light contributions",
+ items=enum_direct_light_sampling_type,
+ default='MULTIPLE_IMPORTANCE_SAMPLING',
+ )
+
min_light_bounces: IntProperty(
name="Min Light Bounces",
description="Minimum number of light bounces. Setting this higher reduces noise in the first bounces, "
@@ -620,6 +667,11 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
description="Use special type BVH optimized for hair (uses more ram but renders faster)",
default=True,
)
+ debug_use_compact_bvh: BoolProperty(
+ name="Use Compact BVH",
+ description="Use compact BVH structure (uses less ram but renders slower)",
+ default=True,
+ )
debug_bvh_time_steps: IntProperty(
name="BVH Time Steps",
description="Split BVH primitives by this number of time steps to speed up render time in cost of memory",
@@ -724,6 +776,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,
@@ -739,15 +799,15 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
)
use_auto_tile: BoolProperty(
- name="Auto Tiles",
- description="Automatically render high resolution images in tiles to reduce memory usage, using the specified tile size. Tiles are cached to disk while rendering to save memory",
+ name="Use Tiling",
+ description="Render high resolution images in tiles to reduce memory usage, using the specified tile size. Tiles are cached to disk while rendering to save memory",
default=True,
)
tile_size: IntProperty(
name="Tile Size",
default=2048,
description="",
- min=8, max=16384,
+ min=8, max=8192,
)
# Various fine-tuning debug flags
@@ -839,6 +899,32 @@ class CyclesCameraSettings(bpy.types.PropertyGroup):
default=pi,
)
+ fisheye_polynomial_k0: FloatProperty(
+ name="Fisheye Polynomial K0",
+ description="Coefficient K0 of the lens polinomial",
+ default=camera.default_fisheye_polynomial[0], precision=6, step=0.1, subtype='ANGLE',
+ )
+ fisheye_polynomial_k1: FloatProperty(
+ name="Fisheye Polynomial K1",
+ description="Coefficient K1 of the lens polinomial",
+ default=camera.default_fisheye_polynomial[1], precision=6, step=0.1, subtype='ANGLE',
+ )
+ fisheye_polynomial_k2: FloatProperty(
+ name="Fisheye Polynomial K2",
+ description="Coefficient K2 of the lens polinomial",
+ default=camera.default_fisheye_polynomial[2], precision=6, step=0.1, subtype='ANGLE',
+ )
+ fisheye_polynomial_k3: FloatProperty(
+ name="Fisheye Polynomial K3",
+ description="Coefficient K3 of the lens polinomial",
+ default=camera.default_fisheye_polynomial[3], precision=6, step=0.1, subtype='ANGLE',
+ )
+ fisheye_polynomial_k4: FloatProperty(
+ name="Fisheye Polynomial K4",
+ description="Coefficient K4 of the lens polinomial",
+ default=camera.default_fisheye_polynomial[4], precision=6, step=0.1, subtype='ANGLE',
+ )
+
@classmethod
def register(cls):
bpy.types.Camera.cycles = PointerProperty(
@@ -1197,12 +1283,6 @@ class CyclesCurveRenderSettings(bpy.types.PropertyGroup):
class CyclesRenderLayerSettings(bpy.types.PropertyGroup):
- pass_debug_render_time: BoolProperty(
- name="Debug Render Time",
- description="Render time in milliseconds per sample and pixel",
- default=False,
- update=update_render_passes,
- )
pass_debug_sample_count: BoolProperty(
name="Debug Sample Count",
description="Number of samples/camera rays per pixel",
@@ -1267,8 +1347,7 @@ class CyclesPreferences(bpy.types.AddonPreferences):
def get_device_types(self, context):
import _cycles
- has_cuda, has_optix, has_hip = _cycles.get_device_types()
-
+ has_cuda, has_optix, has_hip, has_metal = _cycles.get_device_types()
list = [('NONE', "None", "Don't use compute device", 0)]
if has_cuda:
list.append(('CUDA', "CUDA", "Use CUDA for GPU acceleration", 1))
@@ -1276,6 +1355,8 @@ class CyclesPreferences(bpy.types.AddonPreferences):
list.append(('OPTIX', "OptiX", "Use OptiX for GPU acceleration", 3))
if has_hip:
list.append(('HIP', "HIP", "Use HIP for GPU acceleration", 4))
+ if has_metal:
+ list.append(('METAL', "Metal", "Use Metal for GPU acceleration", 5))
return list
@@ -1301,7 +1382,7 @@ class CyclesPreferences(bpy.types.AddonPreferences):
def update_device_entries(self, device_list):
for device in device_list:
- if not device[1] in {'CUDA', 'OPTIX', 'CPU', 'HIP'}:
+ if not device[1] in {'CUDA', 'OPTIX', 'CPU', 'HIP', 'METAL'}:
continue
# Try to find existing Device entry
entry = self.find_existing_device_entry(device)
@@ -1335,7 +1416,7 @@ class CyclesPreferences(bpy.types.AddonPreferences):
elif entry.type == 'CPU':
cpu_devices.append(entry)
# Extend all GPU devices with CPU.
- if compute_device_type != 'CPU' and compute_device_type != 'HIP':
+ if len(devices) and compute_device_type != 'CPU':
devices.extend(cpu_devices)
return devices
@@ -1345,7 +1426,7 @@ class CyclesPreferences(bpy.types.AddonPreferences):
import _cycles
# Ensure `self.devices` is not re-allocated when the second call to
# get_devices_for_type is made, freeing items from the first list.
- for device_type in ('CUDA', 'OPTIX', 'HIP'):
+ for device_type in ('CUDA', 'OPTIX', 'HIP', 'METAL'):
self.update_device_entries(_cycles.available_devices(device_type))
# Deprecated: use refresh_devices instead.
@@ -1353,18 +1434,37 @@ class CyclesPreferences(bpy.types.AddonPreferences):
self.refresh_devices()
return None
+ def get_compute_device_type(self):
+ if self.compute_device_type == '':
+ return 'NONE'
+ return self.compute_device_type
+
def get_num_gpu_devices(self):
import _cycles
- device_list = _cycles.available_devices(self.compute_device_type)
+ compute_device_type = self.get_compute_device_type()
+ device_list = _cycles.available_devices(compute_device_type)
num = 0
for device in device_list:
- if device[1] != self.compute_device_type:
+ if device[1] != compute_device_type:
continue
for dev in self.devices:
if dev.use and dev.id == device[2]:
num += 1
return num
+ def has_multi_device(self):
+ import _cycles
+ compute_device_type = self.get_compute_device_type()
+ device_list = _cycles.available_devices(compute_device_type)
+ for device in device_list:
+ if device[1] == compute_device_type:
+ continue
+ for dev in self.devices:
+ if dev.use and dev.id == device[2]:
+ return True
+
+ return False
+
def has_active_device(self):
return self.get_num_gpu_devices() > 0
@@ -1379,8 +1479,20 @@ class CyclesPreferences(bpy.types.AddonPreferences):
if not found_device:
col = box.column(align=True)
- col.label(text="No compatible GPUs found for path tracing", icon='INFO')
- col.label(text="Cycles will render on the CPU", icon='BLANK1')
+ col.label(text="No compatible GPUs found for Cycles", icon='INFO')
+
+ if device_type == 'CUDA':
+ col.label(text="Requires NVIDIA GPU with compute capability 3.0", icon='BLANK1')
+ elif device_type == 'OPTIX':
+ col.label(text="Requires NVIDIA GPU with compute capability 5.0", icon='BLANK1')
+ col.label(text="and NVIDIA driver version 470 or newer", icon='BLANK1')
+ elif device_type == 'HIP':
+ import sys
+ col.label(text="Requires discrete AMD GPU with RDNA architecture", icon='BLANK1')
+ if sys.platform[:3] == "win":
+ col.label(text="and AMD Radeon Pro 21.Q4 driver or newer", icon='BLANK1')
+ elif device_type == 'METAL':
+ col.label(text="Requires Apple Silicon and macOS 12.0 or newer", icon='BLANK1')
return
for device in devices:
@@ -1390,15 +1502,16 @@ class CyclesPreferences(bpy.types.AddonPreferences):
row = layout.row()
row.prop(self, "compute_device_type", expand=True)
- if self.compute_device_type == 'NONE':
+ compute_device_type = self.get_compute_device_type()
+ if compute_device_type == 'NONE':
return
row = layout.row()
- devices = self.get_devices_for_type(self.compute_device_type)
- self._draw_devices(row, self.compute_device_type, devices)
+ devices = self.get_devices_for_type(compute_device_type)
+ self._draw_devices(row, compute_device_type, devices)
import _cycles
has_peer_memory = 0
- for device in _cycles.available_devices(self.compute_device_type):
+ for device in _cycles.available_devices(compute_device_type):
if device[3] and self.find_existing_device_entry(device).use:
has_peer_memory += 1
if has_peer_memory > 1:
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
index c4a1844480c..aa5f6740933 100644
--- a/intern/cycles/blender/addon/ui.py
+++ b/intern/cycles/blender/addon/ui.py
@@ -26,27 +26,31 @@ from bpy.types import Panel
from bl_ui.properties_grease_pencil_common import GreasePencilSimplifyPanel
from bl_ui.properties_view_layer import ViewLayerCryptomattePanel, ViewLayerAOVPanel
+class CyclesPresetPanel(PresetPanel, Panel):
+ COMPAT_ENGINES = {'CYCLES'}
+ preset_operator = "script.execute_preset"
-class CYCLES_PT_sampling_presets(PresetPanel, Panel):
+ @staticmethod
+ def post_cb(context):
+ # Modify an arbitrary built-in scene property to force a depsgraph
+ # update, because add-on properties don't. (see T62325)
+ render = context.scene.render
+ render.filter_size = render.filter_size
+
+class CYCLES_PT_sampling_presets(CyclesPresetPanel):
bl_label = "Sampling Presets"
preset_subdir = "cycles/sampling"
- preset_operator = "script.execute_preset"
preset_add_operator = "render.cycles_sampling_preset_add"
- COMPAT_ENGINES = {'CYCLES'}
-class CYCLES_PT_viewport_sampling_presets(PresetPanel, Panel):
+class CYCLES_PT_viewport_sampling_presets(CyclesPresetPanel):
bl_label = "Viewport Sampling Presets"
preset_subdir = "cycles/viewport_sampling"
- preset_operator = "script.execute_preset"
preset_add_operator = "render.cycles_viewport_sampling_preset_add"
- COMPAT_ENGINES = {'CYCLES'}
-class CYCLES_PT_integrator_presets(PresetPanel, Panel):
+class CYCLES_PT_integrator_presets(CyclesPresetPanel):
bl_label = "Integrator Presets"
preset_subdir = "cycles/integrator"
- preset_operator = "script.execute_preset"
preset_add_operator = "render.cycles_integrator_preset_add"
- COMPAT_ENGINES = {'CYCLES'}
class CyclesButtonsPanel:
@@ -93,6 +97,11 @@ def use_cpu(context):
return (get_device_type(context) == 'NONE' or cscene.device == 'CPU')
+def use_metal(context):
+ cscene = context.scene.cycles
+
+ return (get_device_type(context) == 'METAL' and cscene.device == 'GPU')
+
def use_cuda(context):
cscene = context.scene.cycles
@@ -109,11 +118,11 @@ def use_optix(context):
return (get_device_type(context) == 'OPTIX' and cscene.device == 'GPU')
-
-def use_sample_all_lights(context):
+def use_multi_device(context):
cscene = context.scene.cycles
-
- return cscene.sample_all_lights_direct or cscene.sample_all_lights_indirect
+ if cscene.device != 'GPU':
+ return False
+ return context.preferences.addons[__package__].preferences.has_multi_device()
def show_device_active(context):
@@ -283,9 +292,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")
+ col = layout.column(align=True)
+ col.prop(cscene, "sample_offset")
+
+ layout.separator()
+
+ heading = layout.column(align=True, heading="Scrambling Distance")
+ heading.active = not (cscene.use_adaptive_sampling and cscene.use_preview_adaptive_sampling)
+ heading.prop(cscene, "auto_scrambling_distance", text="Automatic")
+ sub = heading.row()
+ sub.active = not cscene.use_preview_adaptive_sampling
+ sub.prop(cscene, "preview_scrambling_distance", text="Viewport")
+ heading.prop(cscene, "scrambling_distance", text="Multiplier")
+
layout.separator()
col = layout.column(align=True)
@@ -461,8 +483,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
@@ -470,6 +491,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"
@@ -641,6 +667,10 @@ class CYCLES_RENDER_PT_performance_acceleration_structure(CyclesButtonsPanel, Pa
bl_label = "Acceleration Structure"
bl_parent_id = "CYCLES_RENDER_PT_performance"
+ @classmethod
+ def poll(cls, context):
+ return not use_optix(context) or has_multi_device(context)
+
def draw(self, context):
import _cycles
@@ -653,21 +683,33 @@ class CYCLES_RENDER_PT_performance_acceleration_structure(CyclesButtonsPanel, Pa
col = layout.column()
- use_embree = False
+ use_embree = _cycles.with_embree
+
if use_cpu(context):
- use_embree = _cycles.with_embree
- if not use_embree:
+ col.prop(cscene, "debug_use_spatial_splits")
+ if use_embree:
+ col.prop(cscene, "debug_use_compact_bvh")
+ else:
+ sub = col.column()
+ sub.active = not cscene.debug_use_spatial_splits
+ sub.prop(cscene, "debug_bvh_time_steps")
+
+ col.prop(cscene, "debug_use_hair_bvh")
+
sub = col.column(align=True)
sub.label(text="Cycles built without Embree support")
sub.label(text="CPU raytracing performance will be poor")
+ else:
+ col.prop(cscene, "debug_use_spatial_splits")
+ sub = col.column()
+ sub.active = not cscene.debug_use_spatial_splits
+ sub.prop(cscene, "debug_bvh_time_steps")
- col.prop(cscene, "debug_use_spatial_splits")
- sub = col.column()
- sub.active = not use_embree
- sub.prop(cscene, "debug_use_hair_bvh")
- sub = col.column()
- sub.active = not cscene.debug_use_spatial_splits and not use_embree
- sub.prop(cscene, "debug_bvh_time_steps")
+ col.prop(cscene, "debug_use_hair_bvh")
+
+ # CPU is used in addition to a GPU
+ if use_multi_device(context) and use_embree:
+ col.prop(cscene, "debug_use_compact_bvh")
class CYCLES_RENDER_PT_performance_final_render(CyclesButtonsPanel, Panel):
@@ -792,7 +834,6 @@ class CYCLES_RENDER_PT_passes_data(CyclesButtonsPanel, Panel):
col.prop(view_layer, "use_pass_material_index")
col = layout.column(heading="Debug", align=True)
- col.prop(cycles_view_layer, "pass_debug_render_time", text="Render Time")
col.prop(cycles_view_layer, "pass_debug_sample_count", text="Sample Count")
layout.prop(view_layer, "pass_alpha_threshold")
@@ -982,8 +1023,8 @@ class CYCLES_PT_context_material(CyclesButtonsPanel, Panel):
row.prop(slot, "link", text="", icon=icon_link, icon_only=True)
elif mat:
- split.template_ID(space, "pin_id")
- split.separator()
+ layout.template_ID(space, "pin_id")
+ layout.separator()
class CYCLES_OBJECT_PT_motion_blur(CyclesButtonsPanel, Panel):
@@ -995,7 +1036,7 @@ class CYCLES_OBJECT_PT_motion_blur(CyclesButtonsPanel, Panel):
def poll(cls, context):
ob = context.object
if CyclesButtonsPanel.poll(context) and ob:
- if ob.type in {'MESH', 'CURVE', 'CURVE', 'SURFACE', 'FONT', 'META', 'CAMERA'}:
+ if ob.type in {'MESH', 'CURVE', 'CURVE', 'SURFACE', 'FONT', 'META', 'CAMERA', 'HAIR', 'POINTCLOUD'}:
return True
if ob.instance_type == 'COLLECTION' and ob.instance_collection:
return True
@@ -1034,7 +1075,7 @@ class CYCLES_OBJECT_PT_motion_blur(CyclesButtonsPanel, Panel):
def has_geometry_visibility(ob):
- return ob and ((ob.type in {'MESH', 'CURVE', 'SURFACE', 'FONT', 'META', 'LIGHT'}) or
+ return ob and ((ob.type in {'MESH', 'CURVE', 'SURFACE', 'FONT', 'META', 'LIGHT', 'VOLUME', 'POINTCLOUD', 'HAIR'}) or
(ob.instance_type == 'COLLECTION' and ob.instance_collection))
@@ -1778,18 +1819,45 @@ class CYCLES_RENDER_PT_bake_output(CyclesButtonsPanel, Panel):
rd = scene.render
if rd.use_bake_multires:
- layout.prop(rd, "bake_margin")
layout.prop(rd, "use_bake_clear", text="Clear Image")
-
if rd.bake_type == 'DISPLACEMENT':
layout.prop(rd, "use_bake_lores_mesh")
else:
layout.prop(cbk, "target")
-
if cbk.target == 'IMAGE_TEXTURES':
- layout.prop(cbk, "margin")
layout.prop(cbk, "use_clear", text="Clear Image")
+class CYCLES_RENDER_PT_bake_output_margin(CyclesButtonsPanel, Panel):
+ bl_label = "Margin"
+ bl_context = "render"
+ bl_parent_id = "CYCLES_RENDER_PT_bake_output"
+ COMPAT_ENGINES = {'CYCLES'}
+
+ @classmethod
+ def poll(cls, context):
+ scene = context.scene
+ cbk = scene.render.bake
+ return cbk.target == 'IMAGE_TEXTURES'
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False # No animation.
+
+ scene = context.scene
+ cscene = scene.cycles
+ cbk = scene.render.bake
+ rd = scene.render
+
+ if rd.use_bake_multires:
+ layout.prop(rd, "bake_margin_type", text="Type")
+ layout.prop(rd, "bake_margin", text="Size")
+ else:
+ if cbk.target == 'IMAGE_TEXTURES':
+ layout.prop(cbk, "margin_type", text="Type")
+ layout.prop(cbk, "margin", text="Size")
+
+
class CYCLES_RENDER_PT_debug(CyclesDebugButtonsPanel, Panel):
bl_label = "Debug"
@@ -1799,37 +1867,38 @@ class CYCLES_RENDER_PT_debug(CyclesDebugButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False # No animation.
scene = context.scene
cscene = scene.cycles
- col = layout.column()
+ col = layout.column(heading="CPU")
- col.label(text="CPU Flags:")
row = col.row(align=True)
row.prop(cscene, "debug_use_cpu_sse2", toggle=True)
row.prop(cscene, "debug_use_cpu_sse3", toggle=True)
row.prop(cscene, "debug_use_cpu_sse41", toggle=True)
row.prop(cscene, "debug_use_cpu_avx", toggle=True)
row.prop(cscene, "debug_use_cpu_avx2", toggle=True)
- col.prop(cscene, "debug_bvh_layout")
+ col.prop(cscene, "debug_bvh_layout", text="BVH")
col.separator()
- col = layout.column()
- col.label(text="CUDA Flags:")
+ col = layout.column(heading="CUDA")
col.prop(cscene, "debug_use_cuda_adaptive_compile")
+ col = layout.column(heading="OptiX")
+ col.prop(cscene, "debug_use_optix_debug", text="Module Debug")
col.separator()
- col = layout.column()
- col.label(text="OptiX Flags:")
- col.prop(cscene, "debug_use_optix_debug")
+ col.prop(cscene, "debug_bvh_type", text="Viewport BVH")
col.separator()
- col = layout.column()
- col.prop(cscene, "debug_bvh_type")
+ import _cycles
+ if _cycles.with_debug:
+ col.prop(cscene, "direct_light_sampling_type")
class CYCLES_RENDER_PT_simplify(CyclesButtonsPanel, Panel):
@@ -2157,6 +2226,7 @@ classes = (
CYCLES_RENDER_PT_bake_influence,
CYCLES_RENDER_PT_bake_selected_to_active,
CYCLES_RENDER_PT_bake_output,
+ CYCLES_RENDER_PT_bake_output_margin,
CYCLES_RENDER_PT_debug,
node_panel(CYCLES_MATERIAL_PT_settings),
node_panel(CYCLES_MATERIAL_PT_settings_surface),
diff --git a/intern/cycles/blender/addon/version_update.py b/intern/cycles/blender/addon/version_update.py
index 57da7d7995c..dab62713525 100644
--- a/intern/cycles/blender/addon/version_update.py
+++ b/intern/cycles/blender/addon/version_update.py
@@ -86,7 +86,7 @@ def do_versions(self):
# Device might not currently be available so this can fail
try:
if system.legacy_compute_device_type == 1:
- prop.compute_device_type = 'OPENCL'
+ prop.compute_device_type = 'NONE' # Was OpenCL
elif system.legacy_compute_device_type == 2:
prop.compute_device_type = 'CUDA'
else:
@@ -97,6 +97,12 @@ def do_versions(self):
# Init device list for UI
prop.get_devices(prop.compute_device_type)
+ if bpy.context.preferences.version <= (3, 0, 40):
+ # Disable OpenCL device
+ prop = bpy.context.preferences.addons[__package__].preferences
+ if prop.is_property_set("compute_device_type") and prop['compute_device_type'] == 4:
+ prop.compute_device_type = 'NONE'
+
# We don't modify startup file because it assumes to
# have all the default values only.
if not bpy.data.is_saved:
@@ -235,8 +241,9 @@ def do_versions(self):
cscene.use_denoising = False
if not cscene.is_property_set("use_preview_denoising"):
cscene.use_preview_denoising = False
- if not cscene.is_property_set("sampling_pattern"):
- cscene.sampling_pattern = 'PROGRESSIVE_MUTI_JITTER'
+ if not cscene.is_property_set("sampling_pattern") or \
+ cscene.get('sampling_pattern') >= 2:
+ cscene.sampling_pattern = 'PROGRESSIVE_MULTI_JITTER'
# Removal of square samples.
cscene = scene.cycles
diff --git a/intern/cycles/blender/blender_camera.cpp b/intern/cycles/blender/blender_camera.cpp
deleted file mode 100644
index 4e8df5a99a6..00000000000
--- a/intern/cycles/blender/blender_camera.cpp
+++ /dev/null
@@ -1,933 +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 pano_viewplane;
- BoundBox2D viewport_camera_border;
-
- 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->pano_viewplane.right = 1.0f;
- bcam->pano_viewplane.top = 1.0f;
- bcam->viewport_camera_border.right = 1.0f;
- bcam->viewport_camera_border.top = 1.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 */
- if (viewplane != NULL) {
- *viewplane = bcam->pano_viewplane;
- }
- }
- 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 */
- float dx = 2.0f * (*aspectratio * bcam->shift.x + bcam->offset.x * xaspect * 2.0f);
- 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);
-
-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;
-
- 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);
-
- bcam->pano_viewplane = view_box.make_relative_to(cam_box);
- }
- 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)
-{
- BoundBox2D cam, view;
- float view_aspect, 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;
- blender_camera_view_subset(
- b_engine, b_render, b_scene, b_ob, b_v3d, b_rv3d, width, height, &view_box, &cam_box);
-
- /* 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;
- }
-
- 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_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_gpu_display.cpp b/intern/cycles/blender/blender_gpu_display.cpp
deleted file mode 100644
index 456ca676cce..00000000000
--- a/intern/cycles/blender/blender_gpu_display.cpp
+++ /dev/null
@@ -1,787 +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_gpu_display.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_;
-}
-
-/* --------------------------------------------------------------------
- * BlenderGPUDisplay.
- */
-
-BlenderGPUDisplay::BlenderGPUDisplay(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();
-}
-
-BlenderGPUDisplay::~BlenderGPUDisplay()
-{
- gl_resources_destroy();
-}
-
-/* --------------------------------------------------------------------
- * Update procedure.
- */
-
-bool BlenderGPUDisplay::do_update_begin(const GPUDisplayParams &params,
- int texture_width,
- int texture_height)
-{
- /* Note that it's the responsibility of BlenderGPUDisplay 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 at the GPU display level, 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 BlenderGPUDisplay::do_update_end()
-{
- gl_upload_sync_ = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
- glFlush();
-
- gl_context_disable();
-}
-
-/* --------------------------------------------------------------------
- * Texture update from CPU buffer.
- */
-
-void BlenderGPUDisplay::do_copy_pixels_to_texture(
- const half4 *rgba_pixels, int texture_x, int texture_y, int pixels_width, int pixels_height)
-{
- /* This call copies pixels to a Pixel Buffer Object (PBO) which is much cheaper from CPU time
- * point of view than to copy data directly to the OpenGL texture.
- *
- * The possible downside of this approach is that it might require a higher peak memory when
- * doing partial updates of the texture (although, in practice even partial updates might peak
- * with a full-frame buffer stored on the CPU if the GPU is currently occupied). */
-
- half4 *mapped_rgba_pixels = map_texture_buffer();
- if (!mapped_rgba_pixels) {
- return;
- }
-
- if (texture_x == 0 && texture_y == 0 && pixels_width == texture_.width &&
- pixels_height == texture_.height) {
- const size_t size_in_bytes = sizeof(half4) * texture_.width * texture_.height;
- memcpy(mapped_rgba_pixels, rgba_pixels, size_in_bytes);
- }
- else {
- const half4 *rgba_row = rgba_pixels;
- half4 *mapped_rgba_row = mapped_rgba_pixels + texture_y * texture_.width + texture_x;
- for (int y = 0; y < pixels_height;
- ++y, rgba_row += pixels_width, mapped_rgba_row += texture_.width) {
- memcpy(mapped_rgba_row, rgba_row, sizeof(half4) * pixels_width);
- }
- }
-
- unmap_texture_buffer();
-}
-
-/* --------------------------------------------------------------------
- * Texture buffer mapping.
- */
-
-half4 *BlenderGPUDisplay::do_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 BlenderGPUDisplay 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 BlenderGPUDisplay::do_unmap_texture_buffer()
-{
- glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
-
- glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
-}
-
-/* --------------------------------------------------------------------
- * Graphics interoperability.
- */
-
-DeviceGraphicsInteropDestination BlenderGPUDisplay::do_graphics_interop_get()
-{
- DeviceGraphicsInteropDestination 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 BlenderGPUDisplay::graphics_interop_activate()
-{
- gl_context_enable();
-}
-
-void BlenderGPUDisplay::graphics_interop_deactivate()
-{
- gl_context_disable();
-}
-
-/* --------------------------------------------------------------------
- * Drawing.
- */
-
-void BlenderGPUDisplay::clear()
-{
- texture_.need_clear = true;
-}
-
-void BlenderGPUDisplay::set_zoom(float zoom_x, float zoom_y)
-{
- zoom_ = make_float2(zoom_x, zoom_y);
-}
-
-void BlenderGPUDisplay::do_draw(const GPUDisplayParams &params)
-{
- /* See do_update_begin() for why no locking is required here. */
- const bool transparent = true; // TODO(sergey): Derive this from Film.
-
- 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. */
- return;
- }
-
- if (!gl_draw_resources_ensure()) {
- return;
- }
-
- if (use_gl_context_) {
- gl_context_mutex_.lock();
- }
-
- 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 BlenderGPUDisplay::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 BlenderGPUDisplay::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 BlenderGPUDisplay::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 BlenderGPUDisplay::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 BlenderGPUDisplay::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 BlenderGPUDisplay::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 BlenderGPUDisplay::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 BlenderGPUDisplay::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 BlenderGPUDisplay::vertex_buffer_update(const GPUDisplayParams &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.offset.x;
- vpointer[3] = params.offset.y;
-
- vpointer[4] = 1.0f;
- vpointer[5] = 0.0f;
- vpointer[6] = (float)params.size.x + params.offset.x;
- vpointer[7] = params.offset.y;
-
- vpointer[8] = 1.0f;
- vpointer[9] = 1.0f;
- vpointer[10] = (float)params.size.x + params.offset.x;
- vpointer[11] = (float)params.size.y + params.offset.y;
-
- vpointer[12] = 0.0f;
- vpointer[13] = 1.0f;
- vpointer[14] = params.offset.x;
- vpointer[15] = (float)params.size.y + params.offset.y;
-
- glUnmapBuffer(GL_ARRAY_BUFFER);
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/blender_gpu_display.h b/intern/cycles/blender/blender_gpu_display.h
deleted file mode 100644
index 89420567037..00000000000
--- a/intern/cycles/blender/blender_gpu_display.h
+++ /dev/null
@@ -1,215 +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/gpu_display.h"
-#include "util/util_unique_ptr.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Base class of shader used for GPU display 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;
-};
-
-/* GPU display implementation which is specific for Blender viewport integration. */
-class BlenderGPUDisplay : public GPUDisplay {
- public:
- BlenderGPUDisplay(BL::RenderEngine &b_engine, BL::Scene &b_scene);
- ~BlenderGPUDisplay();
-
- 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 do_update_begin(const GPUDisplayParams &params,
- int texture_width,
- int texture_height) override;
- virtual void do_update_end() override;
-
- virtual void do_copy_pixels_to_texture(const half4 *rgba_pixels,
- int texture_x,
- int texture_y,
- int pixels_width,
- int pixels_height) override;
- virtual void do_draw(const GPUDisplayParams &params) override;
-
- virtual half4 *do_map_texture_buffer() override;
- virtual void do_unmap_texture_buffer() override;
-
- virtual DeviceGraphicsInteropDestination do_graphics_interop_get() 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 GPUDisplayParams &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 GPUDisplay 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_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 95da4a2df84..00000000000
--- a/intern/cycles/blender/blender_object.cpp
+++ /dev/null
@@ -1,770 +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);
-
- Scene::MotionType need_motion = scene->need_motion();
- if (need_motion == Scene::MOTION_NONE || !object->get_geometry()) {
- return;
- }
-
- Geometry *geom = object->get_geometry();
-
- int motion_steps = 0;
- bool use_motion_blur = false;
-
- 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 {
- 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_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 88edc7eafe7..00000000000
--- a/intern/cycles/blender/blender_session.cpp
+++ /dev/null
@@ -1,1113 +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_gpu_display.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);
-
- /* Create GPU display. */
- if (!b_engine.is_preview() && !headless) {
- unique_ptr<BlenderGPUDisplay> gpu_display = make_unique<BlenderGPUDisplay>(b_engine, b_scene);
- gpu_display_ = gpu_display.get();
- session->set_gpu_display(move(gpu_display));
- }
-
- /* 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;
-}
-
-void BlenderSession::read_render_tile()
-{
- const int2 tile_offset = session->get_render_tile_offset();
- const int2 tile_size = session->get_render_tile_size();
-
- /* get render result */
- BL::RenderResult b_rr = b_engine.begin_result(tile_offset.x,
- tile_offset.y,
- tile_size.x,
- tile_size.y,
- b_rlay_name.c_str(),
- b_rview_name.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.
- * TODO:copy only the required ones for better performance? */
- for (BL::RenderPass &b_pass : b_rlay.passes) {
- session->set_render_tile_pixels(b_pass.name(), b_pass.channels(), (float *)b_pass.rect());
- }
-
- b_engine.end_result(b_rr, false, false, false);
-}
-
-void BlenderSession::write_render_tile()
-{
- const int2 tile_offset = session->get_render_tile_offset();
- const int2 tile_size = session->get_render_tile_size();
-
- const string_view render_layer_name = session->get_render_tile_layer();
- const string_view render_view_name = session->get_render_tile_view();
-
- 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,
- render_layer_name.c_str(),
- render_view_name.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;
-
- write_render_result(b_rlay);
-
- b_engine.end_result(b_rr, true, false, true);
-}
-
-void BlenderSession::update_render_tile()
-{
- if (!session->has_multiple_render_tiles()) {
- /* Don't highlight full-frame tile. */
- return;
- }
-
- const int2 tile_offset = session->get_render_tile_offset();
- const int2 tile_size = session->get_render_tile_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);
-}
-
-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;
- }
-
- /* set callback to write out render results */
- session->write_render_tile_cb = [&]() { write_render_tile(); };
-
- /* Use final write for preview renders, otherwise render result wouldn't be be updated on Blender
- * side. */
- /* TODO(sergey): Investigate whether GPUDisplay can be used for the preview as well. */
- if (b_engine.is_preview()) {
- session->update_render_tile_cb = [&]() { write_render_tile(); };
- }
- else {
- session->update_render_tile_cb = [&]() { update_render_tile(); };
- }
-
- 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 callback */
- session->write_render_tile_cb = function_null;
- session->update_render_tile_cb = function_null;
- session->full_buffer_written_cb = function_null;
-}
-
-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->read_render_tile_cb = [&]() { read_render_tile(); };
- session->write_render_tile_cb = [&]() { write_render_tile(); };
- session->set_gpu_display(nullptr);
-
- 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->read_render_tile_cb = function_null;
- session->write_render_tile_cb = function_null;
-}
-
-void BlenderSession::write_render_result(BL::RenderLayer &b_rlay)
-{
- if (!session->copy_render_tile_from_device()) {
- return;
- }
-
- const int2 tile_size = session->get_render_tile_size();
- vector<float> pixels(tile_size.x * tile_size.y * 4);
-
- /* Copy each pass. */
- for (BL::RenderPass &b_pass : b_rlay.passes) {
- if (!session->get_render_tile_pixels(b_pass.name(), b_pass.channels(), &pixels[0])) {
- memset(&pixels[0], 0, pixels.size() * sizeof(float));
- }
-
- b_pass.rect(&pixels[0]);
- }
-}
-
-void BlenderSession::update_render_result(BL::RenderLayer &b_rlay)
-{
- if (!session->copy_render_tile_from_device()) {
- return;
- }
-
- const int2 tile_size = session->get_render_tile_size();
- vector<float> pixels(tile_size.x * tile_size.y * 4);
-
- /* Copy combined pass. */
- BL::RenderPass b_combined_pass(b_rlay.passes.find_by_name("Combined", b_rview_name.c_str()));
- if (session->get_render_tile_pixels("Combined", b_combined_pass.channels(), &pixels[0])) {
- b_combined_pass.rect(&pixels[0]);
- }
-}
-
-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();
- }
-
- /* 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;
- }
-
- BL::Array<float, 2> zoom = space_image.zoom();
- gpu_display_->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();
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/blender_session.h b/intern/cycles/blender/blender_session.h
deleted file mode 100644
index 58683ee07a1..00000000000
--- a/intern/cycles/blender/blender_session.h
+++ /dev/null
@@ -1,175 +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 BlenderGPUDisplay;
-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 write_render_result(BL::RenderLayer &b_rlay);
- void write_render_tile();
-
- void update_render_tile();
-
- void full_buffer_written(string_view filename);
-
- /* update functions are used to update display buffer only after sample was rendered
- * only needed for better visual feedback */
- void update_render_result(BL::RenderLayer &b_rlay);
-
- /* read functions for baking input */
- void read_render_tile();
-
- /* 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();
-
- struct {
- thread_mutex mutex;
- int last_pass_index = -1;
- } draw_state_;
-
- /* NOTE: The BlenderSession references the GPU display. */
- BlenderGPUDisplay *gpu_display_ = 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 8c4f789ffd0..00000000000
--- a/intern/cycles/blender/blender_shader.cpp
+++ /dev/null
@@ -1,1553 +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, true, &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, false, &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_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_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_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 717f301b03e..00000000000
--- a/intern/cycles/blender/blender_sync.cpp
+++ /dev/null
@@ -1,951 +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("Debug Render Time", PASS_RENDER_TIME);
-
- 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_render_time")) {
- b_engine.add_pass("Debug Render Time", 1, "X", b_view_layer.name().c_str());
- pass_add(scene, PASS_RENDER_TIME, "Debug Render Time");
- }
- 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 128fcbd7055..00000000000
--- a/intern/cycles/blender/blender_util.h
+++ /dev/null
@@ -1,698 +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,
- bool rgb_curve,
- float *min_x,
- float *max_x)
-{
- // const int num_curves = cumap.curves.length(); /* Gives linking error so far. */
- const int num_curves = rgb_curve ? 4 : 3;
- *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_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.
- */
- curvemapping_minmax(cumap, rgb_curve, &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..dffcceed42a
--- /dev/null
+++ b/intern/cycles/blender/camera.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/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;
+
+ float fisheye_polynomial_k0;
+ float fisheye_polynomial_k1;
+ float fisheye_polynomial_k2;
+ float fisheye_polynomial_k3;
+ float fisheye_polynomial_k4;
+
+ 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->fisheye_polynomial_k0 = RNA_float_get(&ccamera, "fisheye_polynomial_k0");
+ bcam->fisheye_polynomial_k1 = RNA_float_get(&ccamera, "fisheye_polynomial_k1");
+ bcam->fisheye_polynomial_k2 = RNA_float_get(&ccamera, "fisheye_polynomial_k2");
+ bcam->fisheye_polynomial_k3 = RNA_float_get(&ccamera, "fisheye_polynomial_k3");
+ bcam->fisheye_polynomial_k4 = RNA_float_get(&ccamera, "fisheye_polynomial_k4");
+
+ 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 ||
+ bcam->panorama_type == PANORAMA_FISHEYE_LENS_POLYNOMIAL)) {
+ 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_fisheye_polynomial_k0(bcam->fisheye_polynomial_k0);
+ cam->set_fisheye_polynomial_k1(bcam->fisheye_polynomial_k1);
+ cam->set_fisheye_polynomial_k2(bcam->fisheye_polynomial_k2);
+ cam->set_fisheye_polynomial_k3(bcam->fisheye_polynomial_k3);
+ cam->set_fisheye_polynomial_k4(bcam->fisheye_polynomial_k4);
+
+ 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(3) << "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..65a02d041cc
--- /dev/null
+++ b/intern/cycles/blender/curves.cpp
@@ -0,0 +1,900 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.empty())
+ 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.empty())
+ 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++;
+ }
+ }
+
+ 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) << "Hair memory 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 motion attribute.";
+ }
+ hair->attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION);
+ }
+ else if (motion_step > 0) {
+ /* 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)
+{
+ /* 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) {
+ 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();
+
+ 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)
+{
+ /* Find or add attribute. */
+ Attribute *attr_mP = hair->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ bool new_attribute = false;
+
+ if (!attr_mP) {
+ 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) {
+#ifdef WITH_HAIR_NODES
+ if (b_ob_info.object_data.is_a(&RNA_Hair)) {
+ /* Hair object. */
+ sync_hair(&new_hair, b_ob_info, false);
+ }
+ else
+#endif
+ {
+ /* 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)) {
+#ifdef WITH_HAIR_NODES
+ if (b_ob_info.object_data.is_a(&RNA_Hair)) {
+ /* Hair object. */
+ sync_hair(hair, b_ob_info, true, motion_step);
+ return;
+ }
+ else
+#endif
+ {
+ /* 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..d39381ac6f1
--- /dev/null
+++ b/intern/cycles/blender/device.cpp
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_METAL = 5,
+
+ 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;
+ }
+ else if (compute_device == COMPUTE_DEVICE_METAL) {
+ mask |= DEVICE_MASK_METAL;
+ }
+ 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..3eab2bb8507
--- /dev/null
+++ b/intern/cycles/blender/display_driver.cpp
@@ -0,0 +1,1071 @@
+/*
+ * 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_;
+}
+
+/* --------------------------------------------------------------------
+ * DrawTile.
+ */
+
+/* Higher level representation of a texture from the graphics library. */
+class GLTexture {
+ public:
+ /* Global counter for all allocated OpenGL textures used by instances of this class. */
+ static inline std::atomic<int> num_used = 0;
+
+ GLTexture() = default;
+
+ ~GLTexture()
+ {
+ assert(gl_id == 0);
+ }
+
+ GLTexture(const GLTexture &other) = delete;
+ GLTexture &operator=(GLTexture &other) = delete;
+
+ GLTexture(GLTexture &&other) noexcept
+ : gl_id(other.gl_id), width(other.width), height(other.height)
+ {
+ other.reset();
+ }
+
+ GLTexture &operator=(GLTexture &&other)
+ {
+ if (this == &other) {
+ return *this;
+ }
+
+ gl_id = other.gl_id;
+ width = other.width;
+ height = other.height;
+
+ other.reset();
+
+ return *this;
+ }
+
+ bool gl_resources_ensure()
+ {
+ if (gl_id) {
+ return true;
+ }
+
+ /* Create texture. */
+ glGenTextures(1, &gl_id);
+ if (!gl_id) {
+ LOG(ERROR) << "Error creating texture.";
+ return false;
+ }
+
+ /* Configure the texture. */
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, gl_id);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ /* Clamp to edge so that precision issues when zoomed out (which forces linear interpolation)
+ * does not cause unwanted repetition. */
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ ++num_used;
+
+ return true;
+ }
+
+ void gl_resources_destroy()
+ {
+ if (!gl_id) {
+ return;
+ }
+
+ glDeleteTextures(1, &gl_id);
+
+ reset();
+
+ --num_used;
+ }
+
+ /* OpenGL resource IDs of the texture.
+ *
+ * NOTE: Allocated on the render engine's context. */
+ uint gl_id = 0;
+
+ /* Dimensions of the texture in pixels. */
+ int width = 0;
+ int height = 0;
+
+ protected:
+ void reset()
+ {
+ gl_id = 0;
+ width = 0;
+ height = 0;
+ }
+};
+
+/* Higher level representation of a Pixel Buffer Object (PBO) from the graphics library. */
+class GLPixelBufferObject {
+ public:
+ /* Global counter for all allocated OpenGL PBOs used by instances of this class. */
+ static inline std::atomic<int> num_used = 0;
+
+ GLPixelBufferObject() = default;
+
+ ~GLPixelBufferObject()
+ {
+ assert(gl_id == 0);
+ }
+
+ GLPixelBufferObject(const GLPixelBufferObject &other) = delete;
+ GLPixelBufferObject &operator=(GLPixelBufferObject &other) = delete;
+
+ GLPixelBufferObject(GLPixelBufferObject &&other) noexcept
+ : gl_id(other.gl_id), width(other.width), height(other.height)
+ {
+ other.reset();
+ }
+
+ GLPixelBufferObject &operator=(GLPixelBufferObject &&other)
+ {
+ if (this == &other) {
+ return *this;
+ }
+
+ gl_id = other.gl_id;
+ width = other.width;
+ height = other.height;
+
+ other.reset();
+
+ return *this;
+ }
+
+ bool gl_resources_ensure()
+ {
+ if (gl_id) {
+ return true;
+ }
+
+ glGenBuffers(1, &gl_id);
+ if (!gl_id) {
+ LOG(ERROR) << "Error creating texture pixel buffer object.";
+ return false;
+ }
+
+ ++num_used;
+
+ return true;
+ }
+
+ void gl_resources_destroy()
+ {
+ if (!gl_id) {
+ return;
+ }
+
+ glDeleteBuffers(1, &gl_id);
+
+ reset();
+
+ --num_used;
+ }
+
+ /* OpenGL resource IDs of the PBO.
+ *
+ * NOTE: Allocated on the render engine's context. */
+ uint gl_id = 0;
+
+ /* Dimensions of the PBO. */
+ int width = 0;
+ int height = 0;
+
+ protected:
+ void reset()
+ {
+ gl_id = 0;
+ width = 0;
+ height = 0;
+ }
+};
+
+class DrawTile {
+ public:
+ DrawTile() = default;
+ ~DrawTile() = default;
+
+ DrawTile(const DrawTile &other) = delete;
+ DrawTile &operator=(const DrawTile &other) = delete;
+
+ DrawTile(DrawTile &&other) noexcept = default;
+
+ DrawTile &operator=(DrawTile &&other) = default;
+
+ bool gl_resources_ensure()
+ {
+ if (!texture.gl_resources_ensure()) {
+ gl_resources_destroy();
+ return false;
+ }
+
+ if (!gl_vertex_buffer) {
+ glGenBuffers(1, &gl_vertex_buffer);
+ if (!gl_vertex_buffer) {
+ LOG(ERROR) << "Error allocating tile VBO.";
+ gl_resources_destroy();
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ void gl_resources_destroy()
+ {
+ texture.gl_resources_destroy();
+
+ if (gl_vertex_buffer) {
+ glDeleteBuffers(1, &gl_vertex_buffer);
+ gl_vertex_buffer = 0;
+ }
+ }
+
+ inline bool ready_to_draw() const
+ {
+ return texture.gl_id != 0;
+ }
+
+ /* Texture which contains pixels of the tile. */
+ GLTexture texture;
+
+ /* Display parameters the texture of this tile has been updated for. */
+ BlenderDisplayDriver::Params params;
+
+ /* OpenGL resources needed for drawing. */
+ uint gl_vertex_buffer = 0;
+};
+
+class DrawTileAndPBO {
+ public:
+ bool gl_resources_ensure()
+ {
+ if (!tile.gl_resources_ensure() || !buffer_object.gl_resources_ensure()) {
+ gl_resources_destroy();
+ return false;
+ }
+
+ return true;
+ }
+
+ void gl_resources_destroy()
+ {
+ tile.gl_resources_destroy();
+ buffer_object.gl_resources_destroy();
+ }
+
+ DrawTile tile;
+ GLPixelBufferObject buffer_object;
+};
+
+/* --------------------------------------------------------------------
+ * BlenderDisplayDriver.
+ */
+
+struct BlenderDisplayDriver::Tiles {
+ /* Resources of a tile which is being currently rendered. */
+ DrawTileAndPBO current_tile;
+
+ /* All tiles which rendering is finished and which content will not be changed. */
+ struct {
+ vector<DrawTile> tiles;
+
+ void gl_resources_destroy_and_clear()
+ {
+ for (DrawTile &tile : tiles) {
+ tile.gl_resources_destroy();
+ }
+
+ tiles.clear();
+ }
+ } finished_tiles;
+};
+
+BlenderDisplayDriver::BlenderDisplayDriver(BL::RenderEngine &b_engine, BL::Scene &b_scene)
+ : b_engine_(b_engine),
+ display_shader_(BlenderDisplayShader::create(b_engine, b_scene)),
+ tiles_(make_unique<Tiles>())
+{
+ /* Create context while on the main thread. */
+ gl_context_create();
+}
+
+BlenderDisplayDriver::~BlenderDisplayDriver()
+{
+ gl_resources_destroy();
+}
+
+/* --------------------------------------------------------------------
+ * Update procedure.
+ */
+
+void BlenderDisplayDriver::next_tile_begin()
+{
+ if (!tiles_->current_tile.tile.ready_to_draw()) {
+ LOG(ERROR)
+ << "Unexpectedly moving to the next tile without any data provided for current tile.";
+ return;
+ }
+
+ /* Moving to the next tile without giving render data for the current tile is not an expected
+ * situation. */
+ DCHECK(!need_clear_);
+
+ tiles_->finished_tiles.tiles.emplace_back(std::move(tiles_->current_tile.tile));
+}
+
+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);
+ }
+
+ DrawTile &current_tile = tiles_->current_tile.tile;
+ GLPixelBufferObject &current_tile_buffer_object = tiles_->current_tile.buffer_object;
+
+ /* Clear storage of all finished tiles when display clear is requested.
+ * Do it when new tile data is provided to handle the display clear flag in a single place.
+ * It also makes the logic reliable from the whether drawing did happen or not point of view. */
+ if (need_clear_) {
+ tiles_->finished_tiles.gl_resources_destroy_and_clear();
+ need_clear_ = false;
+ }
+
+ if (!tiles_->current_tile.gl_resources_ensure()) {
+ tiles_->current_tile.gl_resources_destroy();
+ gl_context_disable();
+ return false;
+ }
+
+ /* Update texture dimensions if needed. */
+ if (current_tile.texture.width != texture_width ||
+ current_tile.texture.height != texture_height) {
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, current_tile.texture.gl_id);
+ glTexImage2D(
+ GL_TEXTURE_2D, 0, GL_RGBA16F, texture_width, texture_height, 0, GL_RGBA, GL_HALF_FLOAT, 0);
+ current_tile.texture.width = texture_width;
+ current_tile.texture.height = texture_height;
+ glBindTexture(GL_TEXTURE_2D, 0);
+ }
+
+ /* Update PBO dimensions if needed.
+ *
+ * NOTE: Allocate the PBO for 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.size.x;
+ const int buffer_height = params.size.y;
+ if (current_tile_buffer_object.width != buffer_width ||
+ current_tile_buffer_object.height != buffer_height) {
+ const size_t size_in_bytes = sizeof(half4) * buffer_width * buffer_height;
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, current_tile_buffer_object.gl_id);
+ glBufferData(GL_PIXEL_UNPACK_BUFFER, size_in_bytes, 0, GL_DYNAMIC_DRAW);
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
+
+ current_tile_buffer_object.width = buffer_width;
+ current_tile_buffer_object.height = buffer_height;
+ }
+
+ /* Store an updated parameters of the current tile.
+ * In theory it is only needed once per update of the tile, but doing it on every update is
+ * the easiest and is not expensive. */
+ tiles_->current_tile.tile.params = params;
+
+ return true;
+}
+
+static void update_tile_texture_pixels(const DrawTileAndPBO &tile)
+{
+ const GLTexture &texture = tile.tile.texture;
+
+ DCHECK_NE(tile.buffer_object.gl_id, 0);
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, texture.gl_id);
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, tile.buffer_object.gl_id);
+
+ glTexSubImage2D(
+ GL_TEXTURE_2D, 0, 0, 0, texture.width, texture.height, GL_RGBA, GL_HALF_FLOAT, 0);
+
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
+ glBindTexture(GL_TEXTURE_2D, 0);
+}
+
+void BlenderDisplayDriver::update_end()
+{
+ /* Unpack the PBO into the texture as soon as the new content is provided.
+ *
+ * This allows to ensure that the unpacking happens while resources like graphics interop (which
+ * lifetime is outside of control of the display driver) are still valid, as well as allows to
+ * move the tile from being current to finished immediately after this call.
+ *
+ * One concern with this approach is that if the update happens more often than drawing then
+ * doing the unpack here occupies GPU transfer for no good reason. However, the render scheduler
+ * takes care of ensuring updates don't happen that often. In regular applications redraw will
+ * happen much more often than this update. */
+ update_tile_texture_pixels(tiles_->current_tile);
+
+ gl_upload_sync_ = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+ glFlush();
+
+ gl_context_disable();
+}
+
+/* --------------------------------------------------------------------
+ * Texture buffer mapping.
+ */
+
+half4 *BlenderDisplayDriver::map_texture_buffer()
+{
+ const uint pbo_gl_id = tiles_->current_tile.buffer_object.gl_id;
+
+ DCHECK_NE(pbo_gl_id, 0);
+
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo_gl_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.";
+ }
+
+ 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 = tiles_->current_tile.buffer_object.width;
+ interop_dst.buffer_height = tiles_->current_tile.buffer_object.height;
+ interop_dst.opengl_pbo_id = tiles_->current_tile.buffer_object.gl_id;
+
+ return interop_dst;
+}
+
+void BlenderDisplayDriver::graphics_interop_activate()
+{
+ gl_context_enable();
+}
+
+void BlenderDisplayDriver::graphics_interop_deactivate()
+{
+ gl_context_disable();
+}
+
+/* --------------------------------------------------------------------
+ * Drawing.
+ */
+
+void BlenderDisplayDriver::clear()
+{
+ need_clear_ = true;
+}
+
+void BlenderDisplayDriver::set_zoom(float zoom_x, float zoom_y)
+{
+ zoom_ = make_float2(zoom_x, zoom_y);
+}
+
+/* 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. */
+static void vertex_buffer_update(const DisplayDriver::Params &params)
+{
+ const int x = params.full_offset.x;
+ const int y = params.full_offset.y;
+
+ const int width = params.size.x;
+ const int height = 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);
+}
+
+static void draw_tile(const float2 &zoom,
+ const int texcoord_attribute,
+ const int position_attribute,
+ const DrawTile &draw_tile)
+{
+ if (!draw_tile.ready_to_draw()) {
+ return;
+ }
+
+ const GLTexture &texture = draw_tile.texture;
+
+ DCHECK_NE(texture.gl_id, 0);
+ DCHECK_NE(draw_tile.gl_vertex_buffer, 0);
+
+ glBindBuffer(GL_ARRAY_BUFFER, draw_tile.gl_vertex_buffer);
+
+ /* 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. */
+ vertex_buffer_update(draw_tile.params);
+
+ 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 = draw_tile.params.size.x * zoom.x;
+ const float zoomed_height = draw_tile.params.size.y * zoom.y;
+ if (texture.width != draw_tile.params.size.x || texture.height != draw_tile.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 - draw_tile.params.size.x > 0.5f ||
+ zoomed_height - draw_tile.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);
+ }
+
+ 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);
+}
+
+void BlenderDisplayDriver::flush()
+{
+ /* This is called from the render thread that also calls update_begin/end, right before ending
+ * the render loop. We wait for any queued PBO and render commands to be done, before destroying
+ * the render thread and activating the context in the main thread to destroy resources.
+ *
+ * If we don't do this, the NVIDIA driver hangs for a few seconds for when ending 3D viewport
+ * rendering, for unknown reasons. This was found with NVIDIA driver version 470.73 and a Quadro
+ * RTX 6000 on Linux. */
+ if (!gl_context_enable()) {
+ return;
+ }
+
+ if (gl_upload_sync_) {
+ glWaitSync((GLsync)gl_upload_sync_, 0, GL_TIMEOUT_IGNORED);
+ }
+
+ if (gl_render_sync_) {
+ glWaitSync((GLsync)gl_render_sync_, 0, GL_TIMEOUT_IGNORED);
+ }
+
+ gl_context_disable();
+}
+
+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 (use_gl_context_) {
+ gl_context_mutex_.lock();
+ }
+
+ if (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. */
+ if (use_gl_context_) {
+ 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);
+ }
+
+ glActiveTexture(GL_TEXTURE0);
+
+ /* NOTE: The VAO is to be allocated on the drawing context as it is not shared across contexts.
+ * Simplest is to allocate it on every redraw so that it is possible to destroy it from a
+ * correct context. */
+ GLuint vertex_array_object;
+ glGenVertexArrays(1, &vertex_array_object);
+ glBindVertexArray(vertex_array_object);
+
+ display_shader_->bind(params.full_size.x, params.full_size.y);
+
+ 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);
+
+ draw_tile(zoom_, texcoord_attribute, position_attribute, tiles_->current_tile.tile);
+
+ for (const DrawTile &tile : tiles_->finished_tiles.tiles) {
+ draw_tile(zoom_, texcoord_attribute, position_attribute, tile);
+ }
+
+ display_shader_->unbind();
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glBindVertexArray(0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ glDeleteVertexArrays(1, &vertex_array_object);
+
+ if (transparent) {
+ glDisable(GL_BLEND);
+ }
+
+ gl_render_sync_ = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+ glFlush();
+
+ if (VLOG_IS_ON(5)) {
+ VLOG(5) << "Number of textures: " << GLTexture::num_used;
+ VLOG(5) << "Number of PBOs: " << GLPixelBufferObject::num_used;
+ }
+
+ 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);
+ }
+}
+
+void BlenderDisplayDriver::gl_resources_destroy()
+{
+ gl_context_enable();
+
+ tiles_->current_tile.gl_resources_destroy();
+ tiles_->finished_tiles.gl_resources_destroy_and_clear();
+
+ gl_context_disable();
+
+ gl_context_dispose();
+}
+
+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..2cf6be0d287
--- /dev/null
+++ b/intern/cycles/blender/display_driver.h
@@ -0,0 +1,164 @@
+/*
+ * 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"
+#include "util/vector.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 void next_tile_begin() override;
+
+ 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;
+
+ virtual void flush() override;
+
+ /* Helper function which allocates new GPU context. */
+ void gl_context_create();
+ bool gl_context_enable();
+ void gl_context_disable();
+ void gl_context_dispose();
+
+ /* Destroy all GPU resources which are being used by this object. */
+ void gl_resources_destroy();
+
+ 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_;
+
+ /* Content of the display is to be filled with zeroes. */
+ std::atomic<bool> need_clear_ = true;
+
+ unique_ptr<BlenderDisplayShader> display_shader_;
+
+ /* Opaque storage for an internal state and data for tiles. */
+ struct Tiles;
+ unique_ptr<Tiles> tiles_;
+
+ 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..78c803b7adb
--- /dev/null
+++ b/intern/cycles/blender/geometry.cpp
@@ -0,0 +1,265 @@
+
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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/pointcloud.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)
+{
+#ifdef WITH_HAIR_NODES
+ if (b_ob_info.object_data.is_a(&RNA_Hair) || use_particle_hair) {
+#else
+ if (use_particle_hair) {
+#endif
+ return Geometry::HAIR;
+ }
+
+ if (b_ob_info.object_data.is_a(&RNA_PointCloud)) {
+ return Geometry::POINTCLOUD;
+ }
+
+ 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 if (geom_type == Geometry::POINTCLOUD) {
+ geom = scene->create_node<PointCloud>();
+ }
+ 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 if (geom_type == Geometry::POINTCLOUD) {
+ PointCloud *pointcloud = static_cast<PointCloud *>(geom);
+ sync_pointcloud(pointcloud, b_ob_info);
+ }
+ 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;
+
+#ifdef WITH_HAIR_NODES
+ if (b_ob_info.object_data.is_a(&RNA_Hair) || use_particle_hair) {
+#else
+ if (use_particle_hair) {
+#endif
+ 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 if (b_ob_info.object_data.is_a(&RNA_PointCloud)) {
+ PointCloud *pointcloud = static_cast<PointCloud *>(geom);
+ sync_pointcloud_motion(pointcloud, b_ob_info, motion_step);
+ }
+ 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..4f5744d86a8
--- /dev/null
+++ b/intern/cycles/blender/image.cpp
@@ -0,0 +1,226 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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,
+ const int frame,
+ const bool is_preview_render)
+ : b_image(b_image),
+ frame(frame),
+ /* Don't free cache for preview render to avoid race condition from T93560, to be fixed
+ properly later as we are close to release. */
+ free_cache(!is_preview_render && !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..b4aa4299ed1
--- /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, const int frame, const bool is_preview_render);
+
+ 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..4ec25a868ae
--- /dev/null
+++ b/intern/cycles/blender/mesh.cpp
@@ -0,0 +1,1276 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.empty()) {
+ 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.empty()) {
+ 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.empty()) &&
+ (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_edge_crease(e.vertices()[0], e.vertices()[1], e.crease());
+ }
+ }
+
+ for (BL::MeshVertexCreaseLayer &c : b_mesh.vertex_creases) {
+ for (int i = 0; i < c.data.length(); ++i) {
+ if (c.data[i].value() != 0.0f) {
+ mesh->add_vertex_crease(i, c.data[i].value());
+ }
+ }
+ }
+
+ /* 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 */
+
+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 = object_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..65a04a39660
--- /dev/null
+++ b/intern/cycles/blender/object.cpp
@@ -0,0 +1,802 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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(BObjectInfo &b_ob_info)
+{
+ BL::ID b_ob_data = b_ob_info.object_data;
+
+ if (!b_ob_data) {
+ return false;
+ }
+
+ BL::Object::type_enum type = b_ob_info.iter_object.type();
+
+ if (type == BL::Object::type_VOLUME || type == BL::Object::type_HAIR ||
+ type == BL::Object::type_POINTCLOUD) {
+ /* Will be exported attached to mesh. */
+ return true;
+ }
+
+ /* Other object types that are not meshes but evaluate to meshes are presented to render engines
+ * as separate instance objects. Metaballs and surface objects have not been affected by that
+ * change yet. */
+ if (type == BL::Object::type_SURFACE || type == BL::Object::type_META) {
+ return true;
+ }
+
+ return b_ob_data.is_a(&RNA_Mesh);
+}
+
+bool BlenderSync::object_can_have_geometry(BL::Object &b_ob)
+{
+ BL::Object::type_enum type = b_ob.type();
+ switch (type) {
+ case BL::Object::type_MESH:
+ case BL::Object::type_CURVE:
+ case BL::Object::type_SURFACE:
+ case BL::Object::type_META:
+ case BL::Object::type_FONT:
+ case BL::Object::type_HAIR:
+ case BL::Object::type_POINTCLOUD:
+ case BL::Object::type_VOLUME:
+ return true;
+ default:
+ return false;
+ }
+}
+
+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;
+ if (!b_ob_info.is_real_object_data()) {
+ /* Remember which object data the geometry is coming from, so that we can sync it when the
+ * object has changed. */
+ instance_geometries_by_object[b_ob_info.real_object.ptr.data].insert(b_ob_info.object_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 geometry from */
+ if (!object_is_geometry(b_ob_info)) {
+ 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() || b_parent.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));
+
+ array<ustring> layers;
+ for (BL::CacheFileLayer &layer : cache_file.layers) {
+ if (layer.hide_layer()) {
+ continue;
+ }
+
+ absolute_path = blender_absolute_path(b_data, b_ob, layer.filepath());
+ layers.push_back_slow(ustring(absolute_path));
+ }
+ procedural->set_layers(layers);
+
+ 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();
+ }
+ instance_geometries_by_object.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..f35b48493cb
--- /dev/null
+++ b/intern/cycles/blender/output_driver.cpp
@@ -0,0 +1,124 @@
+/*
+ * 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;
+
+ /* 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 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(static_cast<size_t>(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, false, 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/pointcloud.cpp b/intern/cycles/blender/pointcloud.cpp
new file mode 100644
index 00000000000..a69c4f6eca3
--- /dev/null
+++ b/intern/cycles/blender/pointcloud.cpp
@@ -0,0 +1,303 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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/pointcloud.h"
+#include "scene/attribute.h"
+#include "scene/scene.h"
+
+#include "blender/sync.h"
+#include "blender/util.h"
+
+#include "util/foreach.h"
+#include "util/hash.h"
+
+CCL_NAMESPACE_BEGIN
+
+template<typename TypeInCycles, typename GetValueAtIndex>
+static void fill_generic_attribute(BL::PointCloud &b_pointcloud,
+ TypeInCycles *data,
+ const GetValueAtIndex &get_value_at_index)
+{
+ const int num_points = b_pointcloud.points.length();
+ for (int i = 0; i < num_points; i++) {
+ data[i] = get_value_at_index(i);
+ }
+}
+
+static void attr_create_motion(PointCloud *pointcloud,
+ 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 num_points = pointcloud->get_points().size();
+
+ /* Find or add attribute */
+ float3 *P = &pointcloud->get_points()[0];
+ Attribute *attr_mP = pointcloud->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+
+ if (!attr_mP) {
+ attr_mP = pointcloud->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 * num_points;
+
+ for (int i = 0; i < num_points; i++) {
+ mP[i] = P[i] + get_float3(b_vector_attribute.data[i].vector()) * relative_time;
+ }
+ }
+}
+
+static void copy_attributes(PointCloud *pointcloud,
+ BL::PointCloud b_pointcloud,
+ const bool need_motion,
+ const float motion_scale)
+{
+ AttributeSet &attributes = pointcloud->attributes;
+ static const ustring u_velocity("velocity");
+ for (BL::Attribute &b_attribute : b_pointcloud.attributes) {
+ const ustring name{b_attribute.name().c_str()};
+
+ if (need_motion && name == u_velocity) {
+ attr_create_motion(pointcloud, b_attribute, motion_scale);
+ }
+
+ if (attributes.find(name)) {
+ continue;
+ }
+
+ const AttributeElement element = ATTR_ELEMENT_VERTEX;
+ const BL::Attribute::data_type_enum b_data_type = b_attribute.data_type();
+ 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_pointcloud, data, [&](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_pointcloud, data, [&](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_pointcloud, data, [&](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_pointcloud, data, [&](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_pointcloud, data, [&](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_pointcloud, data, [&](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;
+ }
+ }
+}
+
+static void export_pointcloud(Scene *scene,
+ PointCloud *pointcloud,
+ BL::PointCloud b_pointcloud,
+ const bool need_motion,
+ const float motion_scale)
+{
+ /* TODO: optimize so we can straight memcpy arrays from Blender? */
+
+ /* Add requested attributes. */
+ Attribute *attr_random = NULL;
+ if (pointcloud->need_attribute(scene, ATTR_STD_POINT_RANDOM)) {
+ attr_random = pointcloud->attributes.add(ATTR_STD_POINT_RANDOM);
+ }
+
+ /* Reserve memory. */
+ const int num_points = b_pointcloud.points.length();
+ pointcloud->reserve(num_points);
+
+ /* Export points. */
+ BL::PointCloud::points_iterator b_point_iter;
+ for (b_pointcloud.points.begin(b_point_iter); b_point_iter != b_pointcloud.points.end();
+ ++b_point_iter) {
+ BL::Point b_point = *b_point_iter;
+ const float3 co = get_float3(b_point.co());
+ const float radius = b_point.radius();
+ pointcloud->add_point(co, radius);
+
+ /* Random number per point. */
+ if (attr_random != NULL) {
+ attr_random->add(hash_uint2_to_float(b_point.index(), 0));
+ }
+ }
+
+ /* Export attributes */
+ copy_attributes(pointcloud, b_pointcloud, need_motion, motion_scale);
+}
+
+static void export_pointcloud_motion(PointCloud *pointcloud,
+ BL::PointCloud b_pointcloud,
+ int motion_step)
+{
+ /* Find or add attribute. */
+ Attribute *attr_mP = pointcloud->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ bool new_attribute = false;
+
+ if (!attr_mP) {
+ attr_mP = pointcloud->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION);
+ new_attribute = true;
+ }
+
+ /* Export motion points. */
+ const int num_points = pointcloud->num_points();
+ float3 *mP = attr_mP->data_float3() + motion_step * num_points;
+ bool have_motion = false;
+ int num_motion_points = 0;
+ const array<float3> &pointcloud_points = pointcloud->get_points();
+
+ BL::PointCloud::points_iterator b_point_iter;
+ for (b_pointcloud.points.begin(b_point_iter); b_point_iter != b_pointcloud.points.end();
+ ++b_point_iter) {
+ BL::Point b_point = *b_point_iter;
+
+ if (num_motion_points < num_points) {
+ float3 P = get_float3(b_point.co());
+ P.w = b_point.radius();
+ mP[num_motion_points] = P;
+ have_motion = have_motion || (P != pointcloud_points[num_motion_points]);
+ num_motion_points++;
+ }
+ }
+
+ /* In case of new attribute, we verify if there really was any motion. */
+ if (new_attribute) {
+ if (num_motion_points != num_points || !have_motion) {
+ pointcloud->attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION);
+ }
+ else if (motion_step > 0) {
+ /* 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++) {
+ pointcloud->copy_center_to_motion_step(step);
+ }
+ }
+ }
+
+ /* Export attributes */
+ copy_attributes(pointcloud, b_pointcloud, false, 0.0f);
+}
+
+void BlenderSync::sync_pointcloud(PointCloud *pointcloud, BObjectInfo &b_ob_info)
+{
+ size_t old_numpoints = pointcloud->num_points();
+
+ array<Node *> used_shaders = pointcloud->get_used_shaders();
+
+ PointCloud new_pointcloud;
+ new_pointcloud.set_used_shaders(used_shaders);
+
+ /* TODO: add option to filter out points in the view layer. */
+ BL::PointCloud b_pointcloud(b_ob_info.object_data);
+ /* Motion blur attribute is relative to seconds, we need it relative to frames. */
+ const bool need_motion = object_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;
+ export_pointcloud(scene, &new_pointcloud, b_pointcloud, need_motion, motion_scale);
+
+ /* update original sockets */
+ for (const SocketType &socket : new_pointcloud.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;
+ }
+ pointcloud->set_value(socket, new_pointcloud, socket);
+ }
+
+ pointcloud->attributes.clear();
+ foreach (Attribute &attr, new_pointcloud.attributes.attributes) {
+ pointcloud->attributes.attributes.push_back(std::move(attr));
+ }
+
+ /* tag update */
+ const bool rebuild = (pointcloud && old_numpoints != pointcloud->num_points());
+ pointcloud->tag_update(scene, rebuild);
+}
+
+void BlenderSync::sync_pointcloud_motion(PointCloud *pointcloud,
+ BObjectInfo &b_ob_info,
+ int motion_step)
+{
+ /* Skip if nothing exported. */
+ if (pointcloud->num_points() == 0) {
+ return;
+ }
+
+ /* Export deformed coordinates. */
+ if (ccl::BKE_object_is_deform_modified(b_ob_info, b_scene, preview)) {
+ /* PointCloud object. */
+ BL::PointCloud b_pointcloud(b_ob_info.object_data);
+ export_pointcloud_motion(pointcloud, b_pointcloud, motion_step);
+ }
+ else {
+ /* No deformation on this frame, copy coordinates if other frames did have it. */
+ pointcloud->copy_center_to_motion_step(motion_step);
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/python.cpp b/intern/cycles/blender/python.cpp
new file mode 100644
index 00000000000..f3279ff03a3
--- /dev/null
+++ b/intern/cycles/blender/python.cpp
@@ -0,0 +1,1049 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+ int headless;
+
+ if (!PyArg_ParseTuple(args, "OOi", &path, &user_path, &headless)) {
+ return nullptr;
+ }
+
+ PyObject *path_coerce = nullptr, *user_path_coerce = nullptr;
+ path_init(PyC_UnicodeAsByte(path, &path_coerce),
+ PyC_UnicodeAsByte(user_path, &user_path_coerce));
+ Py_XDECREF(path_coerce);
+ Py_XDECREF(user_path_coerce);
+
+ BlenderSession::headless = headless;
+
+ DebugFlags().running_inside_blender = true;
+
+ 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)
+{
+ static const char *keyword_list[] = {
+ "preferences", "scene", "view_layer", "input", "output", NULL};
+ PyObject *pypreferences, *pyscene, *pyviewlayer;
+ PyObject *pyinput, *pyoutput = NULL;
+
+ if (!PyArg_ParseTupleAndKeywords(args,
+ keywords,
+ "OOOO|O",
+ (char **)keyword_list,
+ &pypreferences,
+ &pyscene,
+ &pyviewlayer,
+ &pyinput,
+ &pyoutput)) {
+ 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);
+ BL::ViewLayer b_view_layer(viewlayerptr);
+
+ DenoiseParams params = BlenderSync::get_denoise_params(b_scene, b_view_layer, true);
+ params.use = true;
+
+ /* 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, params);
+ denoiser.input = input;
+ denoiser.output = output;
+
+ /* Run denoiser. */
+ if (!denoiser.run()) {
+ PyErr_SetString(PyExc_ValueError, denoiser.error.c_str());
+ return NULL;
+ }
+
+ 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);
+
+ debug_flags_set = true;
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *debug_flags_reset_func(PyObject * /*self*/, PyObject * /*args*/)
+{
+ debug_flags_reset();
+ if (debug_flags_set) {
+ 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, has_metal = 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);
+ has_metal |= (device_type == DEVICE_METAL);
+ }
+ PyObject *list = PyTuple_New(4);
+ 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));
+ PyTuple_SET_ITEM(list, 3, PyBool_FromLong(has_metal));
+ 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 if (override == "METAL") {
+ BlenderSession::device_override = DEVICE_MASK_METAL;
+ }
+ 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);
+ }
+
+#ifdef WITH_CYCLES_DEBUG
+ PyModule_AddObject(mod, "with_debug", Py_True);
+ Py_INCREF(Py_True);
+#else /* WITH_CYCLES_DEBUG */
+ PyModule_AddObject(mod, "with_debug", Py_False);
+ Py_INCREF(Py_False);
+#endif /* WITH_CYCLES_DEBUG */
+
+ return (void *)mod;
+}
diff --git a/intern/cycles/blender/session.cpp b/intern/cycles/blender/session.cpp
new file mode 100644
index 00000000000..c81a0f4edb2
--- /dev/null
+++ b/intern/cycles/blender/session.cpp
@@ -0,0 +1,1033 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.0;
+ 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());
+
+ /* Force update in this case, since the camera transform on each frame changes
+ * in different views. This could be optimized by somehow storing the animated
+ * camera transforms separate from the fixed stereo transform. */
+ if ((scene->need_motion() != Scene::MOTION_NONE) && view_index > 0) {
+ sync->tag_update();
+ }
+
+ /* 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 output driver. */
+ session->set_output_driver(nullptr);
+ session->full_buffer_written_cb = function_null;
+
+ /* The display driver holds OpenGL resources which belong to an OpenGL context held by the render
+ * engine on Blender side. Force destruction of those resources. */
+ display_driver_ = nullptr;
+ session->set_display_driver(nullptr);
+
+ /* 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);
+
+ /* Filtering settings for combined pass. */
+ if (pass->get_type() == PASS_COMBINED) {
+ Integrator *integrator = scene->integrator;
+ integrator->set_use_direct_light((bake_filter & BL::BakeSettings::pass_filter_DIRECT) != 0);
+ integrator->set_use_indirect_light((bake_filter & BL::BakeSettings::pass_filter_INDIRECT) !=
+ 0);
+ integrator->set_use_diffuse((bake_filter & BL::BakeSettings::pass_filter_DIFFUSE) != 0);
+ integrator->set_use_glossy((bake_filter & BL::BakeSettings::pass_filter_GLOSSY) != 0);
+ integrator->set_use_transmission(
+ (bake_filter & BL::BakeSettings::pass_filter_TRANSMISSION) != 0);
+ integrator->set_use_emission((bake_filter & BL::BakeSettings::pass_filter_EMIT) != 0);
+ }
+
+ /* Always use transparent background for baking. */
+ scene->background->set_transparent(true);
+
+ /* Load built-in images from Blender. */
+ 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(double &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()
+{
+ double progress = session->progress.get_progress();
+
+ if (progress != last_progress) {
+ b_engine.update_progress((float)progress);
+ last_progress = progress;
+ }
+}
+
+void BlenderSession::update_status_progress()
+{
+ string timestatus, status, substatus;
+ string scene_status = "";
+ double 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((float)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..f837e97c17c
--- /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(double &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;
+ double 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..39e49ac3478
--- /dev/null
+++ b/intern/cycles/blender/shader.cpp
@@ -0,0 +1,1603 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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);
+ if (b_map_range_node.data_type() == BL::ShaderNodeMapRange::data_type_FLOAT_VECTOR) {
+ VectorMapRangeNode *vector_map_range_node = graph->create_node<VectorMapRangeNode>();
+ vector_map_range_node->set_use_clamp(b_map_range_node.clamp());
+ vector_map_range_node->set_range_type(
+ (NodeMapRangeType)b_map_range_node.interpolation_type());
+ node = vector_map_range_node;
+ }
+ else {
+ 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_ShaderNodePointInfo)) {
+ node = graph->create_node<PointInfoNode>();
+ }
+ 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, b_engine.is_preview()),
+ image->image_params());
+ }
+ else {
+ ustring filename = ustring(
+ image_user_file_path(b_image_user, b_image, b_scene.frame_current()));
+ 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, b_engine.is_preview()),
+ env->image_params());
+ }
+ else {
+ env->set_filename(
+ ustring(image_user_file_path(b_image_user, b_image, b_scene.frame_current())));
+ }
+ }
+ 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..7e6f1535d66
--- /dev/null
+++ b/intern/cycles/blender/sync.cpp
@@ -0,0 +1,1004 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+}
+
+void BlenderSync::tag_update()
+{
+ has_updates_ = true;
+}
+
+/* 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 can_have_geometry = object_can_have_geometry(b_ob);
+ const bool is_light = !can_have_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 (can_have_geometry || is_light) {
+ const bool updated_geometry = b_update.is_updated_geometry();
+
+ /* Geometry (mesh, hair, volume). */
+ if (can_have_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);
+
+ /* Sync all contained geometry instances as well when the object changed.. */
+ map<void *, set<BL::ID>>::const_iterator instance_geometries =
+ instance_geometries_by_object.find(b_ob.ptr.data);
+ if (instance_geometries != instance_geometries_by_object.end()) {
+ for (BL::ID geometry : instance_geometries->second) {
+ geometry_map.set_recalc(geometry);
+ }
+ }
+ }
+
+ 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 auto_scrambling_distance = get_boolean(cscene, "auto_scrambling_distance");
+ if (auto_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;
+
+ if (scrambling_distance != 1.0f) {
+ VLOG(3) << "Using 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);
+ }
+
+#ifdef WITH_CYCLES_DEBUG
+ DirectLightSamplingType direct_light_sampling_type = (DirectLightSamplingType)get_enum(
+ cscene, "direct_light_sampling_type", DIRECT_LIGHT_SAMPLING_NUM, DIRECT_LIGHT_SAMPLING_MIS);
+ integrator->set_direct_light_sampling_type(direct_light_sampling_type);
+#endif
+
+ 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_compact_structure = RNA_boolean_get(&cscene, "debug_use_compact_bvh");
+ 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");
+
+ if (background && !b_engine.is_preview()) {
+ /* Viewport and preview renders do not require temp directory and do request session
+ * parameters more often than the background render.
+ * Optimize RNA-C++ usage and memory allocation a bit by saving string access which we know is
+ * not needed for viewport render. */
+ params.temp_dir = b_engine.temporary_directory();
+ }
+
+ /* 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");
+ int sample_offset = get_int(cscene, "sample_offset");
+
+ if (background) {
+ params.samples = samples;
+ params.sample_offset = sample_offset;
+ }
+ else {
+ params.samples = preview_samples;
+ if (params.samples == 0) {
+ params.samples = INT_MAX;
+ }
+ params.sample_offset = 0;
+ }
+
+ /* Clamp sample offset. */
+ params.sample_offset = clamp(params.sample_offset, 0, Integrator::MAX_SAMPLES);
+
+ /* Clamp samples. */
+ params.samples = clamp(params.samples, 0, Integrator::MAX_SAMPLES - params.sample_offset);
+
+ /* 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 = (double)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..3722b938863
--- /dev/null
+++ b/intern/cycles/blender/sync.h
@@ -0,0 +1,284 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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);
+
+ void tag_update();
+
+ /* 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);
+
+ static DenoiseParams get_denoise_params(BL::Scene &b_scene,
+ BL::ViewLayer &b_view_layer,
+ bool background);
+
+ private:
+ /* 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);
+
+ /* Point Cloud */
+ void sync_pointcloud(PointCloud *pointcloud, BObjectInfo &b_ob_info);
+ void sync_pointcloud_motion(PointCloud *pointcloud, BObjectInfo &b_ob_info, int motion_step = 0);
+
+ /* 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_depsgraph,
+ 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(BObjectInfo &b_ob_info);
+ bool object_can_have_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;
+ /** Remember which geometries come from which objects to be able to sync them after changes. */
+ map<void *, set<BL::ID>> instance_geometries_by_object;
+ 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;
+
+ /* 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..59520b94d6f
--- /dev/null
+++ b/intern/cycles/blender/util.h
@@ -0,0 +1,744 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "scene/scene.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_ex(void *iuser, void *ima, char *path, bool resolve_udim);
+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)
+{
+ char filepath[1024];
+ iuser.tile(0);
+ BKE_image_user_frame_calc(ima.ptr.data, iuser.ptr.data, cfra);
+ BKE_image_user_file_path_ex(iuser.ptr.data, ima.ptr.data, filepath, false);
+
+ return string(filepath);
+}
+
+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.empty() && 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;
+}
+
+/* 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 inline bool object_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;
+}
+
+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..b5c80f78f09 100644
--- a/intern/cycles/bvh/CMakeLists.txt
+++ b/intern/cycles/bvh/CMakeLists.txt
@@ -22,34 +22,46 @@ 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_METAL
+ metal.mm
+)
+
+if(WITH_CYCLES_DEVICE_METAL)
+ list(APPEND SRC
+ ${SRC_METAL}
+ )
+ add_definitions(-DWITH_METAL)
+endif()
+
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
+ metal.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..082041f5ed2
--- /dev/null
+++ b/intern/cycles/bvh/build.cpp
@@ -0,0 +1,1262 @@
+/*
+ * 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/pointcloud.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 triangle primitives.
+ */
+ const int num_bvh_steps = params.num_motion_triangle_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_points(BoundBox &root,
+ BoundBox &center,
+ PointCloud *pointcloud,
+ int i)
+{
+ const Attribute *point_attr_mP = NULL;
+ if (pointcloud->has_motion_blur()) {
+ point_attr_mP = pointcloud->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ }
+
+ const float3 *points_data = &pointcloud->points[0];
+ const float *radius_data = &pointcloud->radius[0];
+ const size_t num_points = pointcloud->num_points();
+ const float3 *motion_data = (point_attr_mP) ? point_attr_mP->data_float3() : NULL;
+ const size_t num_steps = pointcloud->get_motion_steps();
+
+ if (point_attr_mP == NULL) {
+ /* Really simple logic for static points. */
+ for (uint j = 0; j < num_points; j++) {
+ const PointCloud::Point point = pointcloud->get_point(j);
+ BoundBox bounds = BoundBox::empty;
+ point.bounds_grow(points_data, radius_data, bounds);
+ if (bounds.valid()) {
+ references.push_back(BVHReference(bounds, j, i, PRIMITIVE_POINT));
+ root.grow(bounds);
+ center.grow(bounds.center2());
+ }
+ }
+ }
+ else if (params.num_motion_point_steps == 0 || params.use_spatial_split) {
+ /* Simple case of motion points: single node for the whole
+ * shutter time. Lowest memory usage but less optimal
+ * rendering.
+ */
+ /* TODO(sergey): Support motion steps for spatially split BVH. */
+ for (uint j = 0; j < num_points; j++) {
+ const PointCloud::Point point = pointcloud->get_point(j);
+ BoundBox bounds = BoundBox::empty;
+ point.bounds_grow(points_data, radius_data, bounds);
+ for (size_t step = 0; step < num_steps - 1; step++) {
+ point.bounds_grow(motion_data + step * num_points, radius_data, bounds);
+ }
+ if (bounds.valid()) {
+ references.push_back(BVHReference(bounds, j, i, PRIMITIVE_MOTION_POINT));
+ root.grow(bounds);
+ center.grow(bounds.center2());
+ }
+ }
+ }
+ else {
+ /* Motion points, trace optimized case: we split point
+ * primitives into separate nodes for each of the time steps.
+ * This way we minimize overlap of neighbor point primitives.
+ */
+ const int num_bvh_steps = params.num_motion_point_steps * 2 + 1;
+ const float num_bvh_steps_inv_1 = 1.0f / (num_bvh_steps - 1);
+
+ for (uint j = 0; j < num_points; j++) {
+ const PointCloud::Point point = pointcloud->get_point(j);
+ const size_t num_steps = pointcloud->get_motion_steps();
+ const float3 *point_steps = point_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.
+ */
+ float4 prev_key = point.motion_key(
+ points_data, radius_data, point_steps, num_points, num_steps, 0.0f, j);
+ BoundBox prev_bounds = BoundBox::empty;
+ point.bounds_grow(prev_key, 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_key = point.motion_key(
+ points_data, radius_data, point_steps, num_points, num_steps, curr_time, j);
+ BoundBox curr_bounds = BoundBox::empty;
+ point.bounds_grow(curr_key, 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;
+ references.push_back(
+ BVHReference(bounds, j, i, PRIMITIVE_MOTION_POINT, 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);
+ }
+ else if (geom->geometry_type == Geometry::POINTCLOUD) {
+ PointCloud *pointcloud = static_cast<PointCloud *>(geom);
+ add_reference_points(root, center, pointcloud, 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);
+ }
+ else if (geom->geometry_type == Geometry::POINTCLOUD) {
+ PointCloud *pointcloud = static_cast<PointCloud *>(geom);
+ return pointcloud->num_points();
+ }
+
+ 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.use_motion_steps();
+
+ /* 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(max(params.max_triangle_leaf_size, params.max_curve_leaf_size),
+ params.max_point_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;
+ size_t num_points = 0;
+ size_t num_motion_points = 0;
+
+ for (int i = 0; i < size; i++) {
+ const BVHReference &ref = references[range.start() + i];
+
+ if (ref.prim_type() & PRIMITIVE_CURVE) {
+ if (ref.prim_type() & PRIMITIVE_MOTION) {
+ num_motion_curves++;
+ }
+ else {
+ num_curves++;
+ }
+ }
+ else if (ref.prim_type() & PRIMITIVE_TRIANGLE) {
+ if (ref.prim_type() & PRIMITIVE_MOTION) {
+ num_motion_triangles++;
+ }
+ else {
+ num_triangles++;
+ }
+ }
+ else if (ref.prim_type() & PRIMITIVE_POINT) {
+ if (ref.prim_type() & PRIMITIVE_MOTION) {
+ num_motion_points++;
+ }
+ else {
+ num_points++;
+ }
+ }
+ }
+
+ 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) &&
+ (num_points <= params.max_point_leaf_size) &&
+ (num_motion_points <= params.max_motion_point_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 over-allocating 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 = PRIMITIVE_INDEX(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..5b9bb59d9f8
--- /dev/null
+++ b/intern/cycles/bvh/build.h
@@ -0,0 +1,144 @@
+/*
+ * 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 PointCloud;
+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_points(BoundBox &root, BoundBox &center, PointCloud *pointcloud, 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..703639e29f3 100644
--- a/intern/cycles/bvh/bvh.cpp
+++ b/intern/cycles/bvh/bvh.cpp
@@ -18,12 +18,13 @@
#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/metal.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
@@ -40,8 +41,12 @@ const char *bvh_layout_name(BVHLayout layout)
return "EMBREE";
case BVH_LAYOUT_OPTIX:
return "OPTIX";
+ case BVH_LAYOUT_METAL:
+ return "METAL";
case BVH_LAYOUT_MULTI_OPTIX:
+ case BVH_LAYOUT_MULTI_METAL:
case BVH_LAYOUT_MULTI_OPTIX_EMBREE:
+ case BVH_LAYOUT_MULTI_METAL_EMBREE:
return "MULTI";
case BVH_LAYOUT_ALL:
return "ALL";
@@ -103,8 +108,17 @@ BVH *BVH::create(const BVHParams &params,
(void)device;
break;
#endif
+ case BVH_LAYOUT_METAL:
+#ifdef WITH_METAL
+ return bvh_metal_create(params, geometry, objects, device);
+#else
+ (void)device;
+ break;
+#endif
case BVH_LAYOUT_MULTI_OPTIX:
+ case BVH_LAYOUT_MULTI_METAL:
case BVH_LAYOUT_MULTI_OPTIX_EMBREE:
+ case BVH_LAYOUT_MULTI_METAL_EMBREE:
return new BVHMulti(params, geometry, objects);
case BVH_LAYOUT_NONE:
case BVH_LAYOUT_ALL:
diff --git a/intern/cycles/bvh/bvh.h b/intern/cycles/bvh/bvh.h
index 94935c26f10..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
@@ -50,13 +50,9 @@ struct PackedBVH {
array<int4> leaf_nodes;
/* object index to BVH node index mapping for instances */
array<int> object_node;
- /* Mapping from primitive index to index in triangle array. */
- array<uint> prim_tri_index;
- /* Continuous storage of triangle vertices. */
- array<float4> prim_tri_verts;
/* primitive type - triangle or strand */
array<int> prim_type;
- /* visibility visibilitys for primitives */
+ /* Visibility visibilities for primitives. */
array<uint> prim_visibility;
/* mapping from BVH primitive index to true primitive index, as primitives
* may be duplicated due to spatial splits. -1 for instances. */
diff --git a/intern/cycles/bvh/bvh2.cpp b/intern/cycles/bvh/bvh2.cpp
index 379ae9b25ff..f1ea43da1d9 100644
--- a/intern/cycles/bvh/bvh2.cpp
+++ b/intern/cycles/bvh/bvh2.cpp
@@ -17,16 +17,17 @@
#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 "scene/pointcloud.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
@@ -386,7 +387,7 @@ void BVH2::refit_primitives(int start, int end, BoundBox &bbox, uint &visibility
}
else {
/* Primitives. */
- if (pack.prim_type[prim] & PRIMITIVE_ALL_CURVE) {
+ if (pack.prim_type[prim] & PRIMITIVE_CURVE) {
/* Curves. */
const Hair *hair = static_cast<const Hair *>(ob->get_geometry());
int prim_offset = (params.top_level) ? hair->prim_offset : 0;
@@ -409,6 +410,30 @@ void BVH2::refit_primitives(int start, int end, BoundBox &bbox, uint &visibility
}
}
}
+ else if (pack.prim_type[prim] & PRIMITIVE_POINT) {
+ /* Points. */
+ const PointCloud *pointcloud = static_cast<const PointCloud *>(ob->get_geometry());
+ int prim_offset = (params.top_level) ? pointcloud->prim_offset : 0;
+ const float3 *points = &pointcloud->points[0];
+ const float *radius = &pointcloud->radius[0];
+ PointCloud::Point point = pointcloud->get_point(pidx - prim_offset);
+
+ point.bounds_grow(points, radius, bbox);
+
+ /* Motion points. */
+ if (pointcloud->get_use_motion_blur()) {
+ Attribute *attr = pointcloud->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+
+ if (attr) {
+ size_t pointcloud_size = pointcloud->points.size();
+ size_t steps = pointcloud->get_motion_steps() - 1;
+ float3 *point_steps = attr->data_float3();
+
+ for (size_t i = 0; i < steps; i++)
+ point.bounds_grow(point_steps + i * pointcloud_size, radius, bbox);
+ }
+ }
+ }
else {
/* Triangles. */
const Mesh *mesh = static_cast<const Mesh *>(ob->get_geometry());
@@ -439,61 +464,20 @@ void BVH2::refit_primitives(int start, int end, BoundBox &bbox, uint &visibility
/* Triangles */
-void BVH2::pack_triangle(int idx, float4 tri_verts[3])
-{
- int tob = pack.prim_object[idx];
- assert(tob >= 0 && tob < objects.size());
- const Mesh *mesh = static_cast<const Mesh *>(objects[tob]->get_geometry());
-
- int tidx = pack.prim_index[idx];
- Mesh::Triangle t = mesh->get_triangle(tidx);
- const float3 *vpos = &mesh->verts[0];
- float3 v0 = vpos[t.v[0]];
- float3 v1 = vpos[t.v[1]];
- float3 v2 = vpos[t.v[2]];
-
- tri_verts[0] = float3_to_float4(v0);
- tri_verts[1] = float3_to_float4(v1);
- tri_verts[2] = float3_to_float4(v2);
-}
-
void BVH2::pack_primitives()
{
const size_t tidx_size = pack.prim_index.size();
- size_t num_prim_triangles = 0;
- /* Count number of triangles primitives in BVH. */
- for (unsigned int i = 0; i < tidx_size; i++) {
- if ((pack.prim_index[i] != -1)) {
- if ((pack.prim_type[i] & PRIMITIVE_ALL_TRIANGLE) != 0) {
- ++num_prim_triangles;
- }
- }
- }
/* Reserve size for arrays. */
- pack.prim_tri_index.clear();
- pack.prim_tri_index.resize(tidx_size);
- pack.prim_tri_verts.clear();
- pack.prim_tri_verts.resize(num_prim_triangles * 3);
pack.prim_visibility.clear();
pack.prim_visibility.resize(tidx_size);
/* Fill in all the arrays. */
- size_t prim_triangle_index = 0;
for (unsigned int i = 0; i < tidx_size; i++) {
if (pack.prim_index[i] != -1) {
int tob = pack.prim_object[i];
Object *ob = objects[tob];
- if ((pack.prim_type[i] & PRIMITIVE_ALL_TRIANGLE) != 0) {
- pack_triangle(i, (float4 *)&pack.prim_tri_verts[3 * prim_triangle_index]);
- pack.prim_tri_index[i] = 3 * prim_triangle_index;
- ++prim_triangle_index;
- }
- else {
- pack.prim_tri_index[i] = -1;
- }
pack.prim_visibility[i] = ob->visibility_for_tracing();
}
else {
- pack.prim_tri_index[i] = -1;
pack.prim_visibility[i] = 0;
}
}
@@ -522,10 +506,8 @@ void BVH2::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
/* reserve */
size_t prim_index_size = pack.prim_index.size();
- size_t prim_tri_verts_size = pack.prim_tri_verts.size();
size_t pack_prim_index_offset = prim_index_size;
- size_t pack_prim_tri_verts_offset = prim_tri_verts_size;
size_t pack_nodes_offset = nodes_size;
size_t pack_leaf_nodes_offset = leaf_nodes_size;
size_t object_offset = 0;
@@ -535,7 +517,6 @@ void BVH2::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
if (geom->need_build_bvh(params.bvh_layout)) {
prim_index_size += bvh->pack.prim_index.size();
- prim_tri_verts_size += bvh->pack.prim_tri_verts.size();
nodes_size += bvh->pack.nodes.size();
leaf_nodes_size += bvh->pack.leaf_nodes.size();
}
@@ -545,13 +526,12 @@ void BVH2::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
pack.prim_type.resize(prim_index_size);
pack.prim_object.resize(prim_index_size);
pack.prim_visibility.resize(prim_index_size);
- pack.prim_tri_verts.resize(prim_tri_verts_size);
- pack.prim_tri_index.resize(prim_index_size);
pack.nodes.resize(nodes_size);
pack.leaf_nodes.resize(leaf_nodes_size);
pack.object_node.resize(objects.size());
- if (params.num_motion_curve_steps > 0 || params.num_motion_triangle_steps > 0) {
+ if (params.num_motion_curve_steps > 0 || params.num_motion_triangle_steps > 0 ||
+ params.num_motion_point_steps > 0) {
pack.prim_time.resize(prim_index_size);
}
@@ -559,8 +539,6 @@ void BVH2::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
int *pack_prim_type = (pack.prim_type.size()) ? &pack.prim_type[0] : NULL;
int *pack_prim_object = (pack.prim_object.size()) ? &pack.prim_object[0] : NULL;
uint *pack_prim_visibility = (pack.prim_visibility.size()) ? &pack.prim_visibility[0] : NULL;
- float4 *pack_prim_tri_verts = (pack.prim_tri_verts.size()) ? &pack.prim_tri_verts[0] : NULL;
- uint *pack_prim_tri_index = (pack.prim_tri_index.size()) ? &pack.prim_tri_index[0] : NULL;
int4 *pack_nodes = (pack.nodes.size()) ? &pack.nodes[0] : NULL;
int4 *pack_leaf_nodes = (pack.leaf_nodes.size()) ? &pack.leaf_nodes[0] : NULL;
float2 *pack_prim_time = (pack.prim_time.size()) ? &pack.prim_time[0] : NULL;
@@ -609,20 +587,10 @@ void BVH2::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
int *bvh_prim_index = &bvh->pack.prim_index[0];
int *bvh_prim_type = &bvh->pack.prim_type[0];
uint *bvh_prim_visibility = &bvh->pack.prim_visibility[0];
- uint *bvh_prim_tri_index = &bvh->pack.prim_tri_index[0];
float2 *bvh_prim_time = bvh->pack.prim_time.size() ? &bvh->pack.prim_time[0] : NULL;
for (size_t i = 0; i < bvh_prim_index_size; i++) {
- if (bvh->pack.prim_type[i] & PRIMITIVE_ALL_CURVE) {
- pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + geom_prim_offset;
- pack_prim_tri_index[pack_prim_index_offset] = -1;
- }
- else {
- pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + geom_prim_offset;
- pack_prim_tri_index[pack_prim_index_offset] = bvh_prim_tri_index[i] +
- pack_prim_tri_verts_offset;
- }
-
+ pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + geom_prim_offset;
pack_prim_type[pack_prim_index_offset] = bvh_prim_type[i];
pack_prim_visibility[pack_prim_index_offset] = bvh_prim_visibility[i];
pack_prim_object[pack_prim_index_offset] = 0; // unused for instances
@@ -633,15 +601,6 @@ void BVH2::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
}
}
- /* Merge triangle vertices data. */
- if (bvh->pack.prim_tri_verts.size()) {
- const size_t prim_tri_size = bvh->pack.prim_tri_verts.size();
- memcpy(pack_prim_tri_verts + pack_prim_tri_verts_offset,
- &bvh->pack.prim_tri_verts[0],
- prim_tri_size * sizeof(float4));
- pack_prim_tri_verts_offset += prim_tri_size;
- }
-
/* merge nodes */
if (bvh->pack.leaf_nodes.size()) {
int4 *leaf_nodes_offset = &bvh->pack.leaf_nodes[0];
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 d3497f3a8d8..00000000000
--- a/intern/cycles/bvh/bvh_build.cpp
+++ /dev/null
@@ -1,1140 +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 i)
-{
- 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, i, PRIMITIVE_TRIANGLE));
- 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, i, PRIMITIVE_MOTION_TRIANGLE));
- 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, i, PRIMITIVE_MOTION_TRIANGLE, 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 i)
-{
- 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 =
- (curve_attr_mP != NULL) ?
- ((hair->curve_shape == CURVE_RIBBON) ? PRIMITIVE_MOTION_CURVE_RIBBON :
- PRIMITIVE_MOTION_CURVE_THICK) :
- ((hair->curve_shape == CURVE_RIBBON) ? PRIMITIVE_CURVE_RIBBON : PRIMITIVE_CURVE_THICK);
-
- 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, i, 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, i, 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, i, 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 i)
-{
- if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
- Mesh *mesh = static_cast<Mesh *>(geom);
- add_reference_triangles(root, center, mesh, i);
- }
- else if (geom->geometry_type == Geometry::HAIR) {
- Hair *hair = static_cast<Hair *>(geom);
- add_reference_curves(root, center, hair, i);
- }
-}
-
-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 96852510b63..00000000000
--- a/intern/cycles/bvh/bvh_embree.cpp
+++ /dev/null
@@ -1,727 +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 KernelGlobals *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, all light is blocked. */
- const int flags = intersection_get_shader_flags(kg, &current_isect);
- if (!(flags & (SD_HAS_TRANSPARENT_SHADOW)) || ctx->max_hits == 0) {
- ctx->opaque_hit = true;
- return;
- }
-
- /* Test if we need to record this transparent intersection. */
- if (ctx->num_hits < ctx->max_hits || ray->tfar < ctx->max_t) {
- /* Skip already recorded intersections. */
- int num_recorded_hits = min(ctx->num_hits, ctx->max_hits);
-
- for (int i = 0; i < num_recorded_hits; ++i) {
- if (current_isect.object == ctx->isect_s[i].object &&
- current_isect.prim == ctx->isect_s[i].prim && current_isect.t == ctx->isect_s[i].t) {
- /* This intersection was already recorded, skip it. */
- *args->valid = 0;
- return;
- }
- }
-
- /* If maximum number of hits was reached, replace the intersection with the
- * highest distance. We want to find the N closest intersections. */
- int isect_index = num_recorded_hits;
- if (num_recorded_hits + 1 >= ctx->max_hits) {
- float max_t = ctx->isect_s[0].t;
- int max_recorded_hit = 0;
-
- for (int 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 >= ctx->max_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 hits, even beyond ray.max_hits so that
- * the caller can detect this as and consider it opaque, or trace another
- * ray. */
- ++ctx->num_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);
- int object = (current_isect.object == OBJECT_NONE) ?
- kernel_tex_fetch(__prim_object, current_isect.prim) :
- current_isect.object;
- if (ctx->local_object_id != 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;
- }
-
- /* See triangle_intersect_subsurface() for the native equivalent. */
- for (int i = min(ctx->max_hits, ctx->local_isect->num_hits) - 1; i >= 0; --i) {
- if (ctx->local_isect->hits[i].t == ray->tfar) {
- /* This tells Embree to continue tracing. */
- *args->valid = 0;
- break;
- }
- }
-
- int hit_idx = 0;
-
- if (ctx->lcg_state) {
-
- ++ctx->local_isect->num_hits;
- if (ctx->local_isect->num_hits <= ctx->max_hits) {
- hit_idx = ctx->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) % ctx->local_isect->num_hits;
-
- if (hit_idx >= ctx->max_hits) {
- /* This tells Embree to continue tracing. */
- *args->valid = 0;
- break;
- }
- }
- }
- else {
- ctx->local_isect->num_hits = 1;
- }
- /* record intersection */
- ctx->local_isect->hits[hit_idx] = current_isect;
- ctx->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);
- for (size_t i = 0; i < ctx->max_hits; ++i) {
- if (current_isect.object == ctx->isect_s[i].object &&
- current_isect.prim == ctx->isect_s[i].prim && current_isect.t == ctx->isect_s[i].t) {
- /* This intersection was already recorded, skip it. */
- *args->valid = 0;
- break;
- }
- }
- Intersection *isect = &ctx->isect_s[ctx->num_hits];
- ++ctx->num_hits;
- *isect = current_isect;
- /* Only primitives from volume object. */
- uint tri_object = (isect->object == OBJECT_NONE) ?
- kernel_tex_fetch(__prim_object, isect->prim) :
- 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 backfacing 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 backfacing 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->optix_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->optix_prim_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->optix_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->optix_prim_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..616b6273e6a
--- /dev/null
+++ b/intern/cycles/bvh/embree.cpp
@@ -0,0 +1,874 @@
+/*
+ * 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 "scene/pointcloud.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_intersection_func(const RTCFilterFunctionNArguments *args)
+{
+ /* Current implementation in Cycles assumes only single-ray intersection queries. */
+ assert(args->N == 1);
+
+ RTCHit *hit = (RTCHit *)args->hit;
+ CCLIntersectContext *ctx = ((IntersectContext *)args->context)->userRayExt;
+ const KernelGlobalsCPU *kg = ctx->kg;
+ const Ray *cray = ctx->ray;
+
+ if (kernel_embree_is_self_intersection(kg, hit, cray)) {
+ *args->valid = 0;
+ }
+}
+
+/* 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;
+ const Ray *cray = ctx->ray;
+
+ switch (ctx->type) {
+ case CCLIntersectContext::RAY_SHADOW_ALL: {
+ Intersection current_isect;
+ kernel_embree_convert_hit(kg, ray, hit, &current_isect);
+ if (intersection_skip_self_shadow(cray->self, current_isect.object, current_isect.prim)) {
+ *args->valid = 0;
+ return;
+ }
+ /* 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_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;
+ }
+ }
+ if (intersection_skip_self_local(cray->self, current_isect.prim)) {
+ *args->valid = 0;
+ return;
+ }
+
+ /* 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);
+ if (intersection_skip_self(cray->self, current_isect.object, current_isect.prim)) {
+ *args->valid = 0;
+ return;
+ }
+
+ 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:
+ if (kernel_embree_is_self_intersection(kg, hit, cray)) {
+ *args->valid = 0;
+ return;
+ }
+ break;
+ }
+}
+
+static void rtc_filter_func_backface_cull(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;
+ }
+
+ CCLIntersectContext *ctx = ((IntersectContext *)args->context)->userRayExt;
+ const KernelGlobalsCPU *kg = ctx->kg;
+ const Ray *cray = ctx->ray;
+
+ if (kernel_embree_is_self_intersection(kg, hit, cray)) {
+ *args->valid = 0;
+ }
+}
+
+static void rtc_filter_occluded_func_backface_cull(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.0;
+
+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;
+ const bool compact = params.use_compact_structure;
+
+ scene = rtcNewScene(rtc_device);
+ const RTCSceneFlags scene_flags = (dynamic ? RTC_SCENE_FLAG_DYNAMIC : RTC_SCENE_FLAG_NONE) |
+ (compact ? RTC_SCENE_FLAG_COMPACT : RTC_SCENE_FLAG_NONE) |
+ 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);
+ }
+ }
+ else if (geom->geometry_type == Geometry::POINTCLOUD) {
+ PointCloud *pointcloud = static_cast<PointCloud *>(geom);
+ if (pointcloud->num_points() > 0) {
+ add_points(ob, pointcloud, 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);
+ rtcSetGeometryIntersectFilterFunction(geom_id, rtc_filter_intersection_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::set_point_vertex_buffer(RTCGeometry geom_id,
+ const PointCloud *pointcloud,
+ const bool update)
+{
+ const Attribute *attr_mP = NULL;
+ size_t num_motion_steps = 1;
+ if (pointcloud->has_motion_blur()) {
+ attr_mP = pointcloud->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ if (attr_mP) {
+ num_motion_steps = pointcloud->get_motion_steps();
+ }
+ }
+
+ const size_t num_points = pointcloud->num_points();
+
+ /* Copy the point data to Embree */
+ const int t_mid = (num_motion_steps - 1) / 2;
+ const float *radius = pointcloud->get_radius().data();
+ for (int t = 0; t < num_motion_steps; ++t) {
+ const float3 *verts;
+ if (t == t_mid || attr_mP == NULL) {
+ verts = pointcloud->get_points().data();
+ }
+ else {
+ int t_ = (t > t_mid) ? (t - 1) : t;
+ verts = &attr_mP->data_float3()[t_ * num_points];
+ }
+
+ 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_points);
+
+ assert(rtc_verts);
+ if (rtc_verts) {
+ for (size_t j = 0; j < num_points; ++j) {
+ rtc_verts[j] = float3_to_float4(verts[j]);
+ rtc_verts[j].w = radius[j];
+ }
+ }
+
+ if (update) {
+ rtcUpdateGeometryBuffer(geom_id, RTC_BUFFER_TYPE_VERTEX, t);
+ }
+ }
+}
+
+void BVHEmbree::add_points(const Object *ob, const PointCloud *pointcloud, int i)
+{
+ size_t prim_offset = pointcloud->prim_offset;
+
+ const Attribute *attr_mP = NULL;
+ size_t num_motion_steps = 1;
+ if (pointcloud->has_motion_blur()) {
+ attr_mP = pointcloud->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ if (attr_mP) {
+ num_motion_steps = pointcloud->get_motion_steps();
+ }
+ }
+
+ enum RTCGeometryType type = RTC_GEOMETRY_TYPE_SPHERE_POINT;
+
+ RTCGeometry geom_id = rtcNewGeometry(rtc_device, type);
+
+ rtcSetGeometryBuildQuality(geom_id, build_quality);
+ rtcSetGeometryTimeStepCount(geom_id, num_motion_steps);
+
+ set_point_vertex_buffer(geom_id, pointcloud, false);
+
+ rtcSetGeometryUserData(geom_id, (void *)prim_offset);
+ rtcSetGeometryIntersectFilterFunction(geom_id, rtc_filter_func_backface_cull);
+ rtcSetGeometryOccludedFilterFunction(geom_id, rtc_filter_occluded_func_backface_cull);
+ rtcSetGeometryMask(geom_id, ob->visibility_for_tracing());
+
+ rtcCommitGeometry(geom_id);
+ rtcAttachGeometryByID(scene, geom_id, i * 2);
+ rtcReleaseGeometry(geom_id);
+}
+
+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) {
+ rtcSetGeometryIntersectFilterFunction(geom_id, rtc_filter_intersection_func);
+ rtcSetGeometryOccludedFilterFunction(geom_id, rtc_filter_occluded_func);
+ }
+ else {
+ rtcSetGeometryIntersectFilterFunction(geom_id, rtc_filter_func_backface_cull);
+ rtcSetGeometryOccludedFilterFunction(geom_id, rtc_filter_occluded_func_backface_cull);
+ }
+ 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);
+ }
+ }
+ else if (geom->geometry_type == Geometry::POINTCLOUD) {
+ PointCloud *pointcloud = static_cast<PointCloud *>(geom);
+ if (pointcloud->num_points() > 0) {
+ RTCGeometry geom = rtcGetGeometry(scene, geom_id);
+ set_point_vertex_buffer(geom, pointcloud, true);
+ 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..3b30b2bbcf7
--- /dev/null
+++ b/intern/cycles/bvh/embree.h
@@ -0,0 +1,73 @@
+/*
+ * 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 PointCloud;
+
+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_points(const Object *ob, const PointCloud *pointcloud, 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);
+ void set_point_vertex_buffer(RTCGeometry geom_id,
+ const PointCloud *pointcloud,
+ 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/metal.h b/intern/cycles/bvh/metal.h
new file mode 100644
index 00000000000..8de07927e61
--- /dev/null
+++ b/intern/cycles/bvh/metal.h
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+#ifndef __BVH_METAL_H__
+#define __BVH_METAL_H__
+
+#ifdef WITH_METAL
+
+# include "bvh/bvh.h"
+
+CCL_NAMESPACE_BEGIN
+
+BVH *bvh_metal_create(const BVHParams &params,
+ const vector<Geometry *> &geometry,
+ const vector<Object *> &objects,
+ Device *device);
+
+CCL_NAMESPACE_END
+
+#endif /* WITH_METAL */
+
+#endif /* __BVH_METAL_H__ */
diff --git a/intern/cycles/bvh/metal.mm b/intern/cycles/bvh/metal.mm
new file mode 100644
index 00000000000..90a52012f12
--- /dev/null
+++ b/intern/cycles/bvh/metal.mm
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+#ifdef WITH_METAL
+
+# include "device/metal/bvh.h"
+
+CCL_NAMESPACE_BEGIN
+
+BVH *bvh_metal_create(const BVHParams &params,
+ const vector<Geometry *> &geometry,
+ const vector<Object *> &objects,
+ Device *device)
+{
+ return new BVHMetal(params, geometry, objects, device);
+}
+
+CCL_NAMESPACE_END
+
+#endif /* WITH_METAL */
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..60b0843bde2
--- /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 while 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..1fd9efdb75e
--- /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's
+ * 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..671e1a42a31
--- /dev/null
+++ b/intern/cycles/bvh/optix.cpp
@@ -0,0 +1,49 @@
+/*
+ * 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(make_unique<device_only_memory<char>>(
+ device, params.top_level ? "optix tlas" : "optix blas", false)),
+ motion_transform_data(
+ make_unique<device_only_memory<char>>(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..cb855d786bf
--- /dev/null
+++ b/intern/cycles/bvh/optix.h
@@ -0,0 +1,52 @@
+/*
+ * 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"
+
+# include "util/unique_ptr.h"
+
+CCL_NAMESPACE_BEGIN
+
+class BVHOptiX : public BVH {
+ public:
+ Device *device;
+ uint64_t traversable_handle;
+ unique_ptr<device_only_memory<char>> as_data;
+ unique_ptr<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..9804c7994ef
--- /dev/null
+++ b/intern/cycles/bvh/params.h
@@ -0,0 +1,349 @@
+/*
+ * 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;
+ int max_point_leaf_size;
+ int max_motion_point_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;
+
+ /* Use compact acceleration structure (Embree)*/
+ bool use_compact_structure;
+
+ /* Split time range to this number of steps and create leaf node for each
+ * of this time steps.
+ *
+ * Speeds up rendering of motion primitives in the cost of higher memory usage.
+ */
+
+ /* Same as above, but for triangle primitives. */
+ int num_motion_triangle_steps;
+ int num_motion_curve_steps;
+ int num_motion_point_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;
+ max_point_leaf_size = 8;
+ max_motion_point_leaf_size = 8;
+
+ top_level = false;
+ bvh_layout = BVH_LAYOUT_BVH2;
+ use_unaligned_nodes = false;
+
+ num_motion_curve_steps = 0;
+ num_motion_triangle_steps = 0;
+ num_motion_point_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);
+ }
+
+ bool use_motion_steps()
+ {
+ return num_motion_curve_steps > 0 || num_motion_triangle_steps > 0 ||
+ num_motion_point_steps > 0;
+ }
+
+ /* 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..e126b6f18bc
--- /dev/null
+++ b/intern/cycles/bvh/split.cpp
@@ -0,0 +1,566 @@
+/*
+ * 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 "scene/pointcloud.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_point_primitive(const PointCloud *pointcloud,
+ const Transform *tfm,
+ int prim_index,
+ int dim,
+ float pos,
+ BoundBox &left_bounds,
+ BoundBox &right_bounds)
+{
+ /* No real splitting support for points, assume they are small enough for it
+ * not to matter. */
+ float3 point = pointcloud->get_points()[prim_index];
+
+ if (tfm != NULL) {
+ point = transform_point(tfm, point);
+ }
+ point = get_unaligned_point(point);
+
+ if (point[dim] <= pos) {
+ left_bounds.grow(point);
+ }
+
+ if (point[dim] >= pos) {
+ right_bounds.grow(point);
+ }
+}
+
+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_point_reference(const BVHReference &ref,
+ const PointCloud *pointcloud,
+ int dim,
+ float pos,
+ BoundBox &left_bounds,
+ BoundBox &right_bounds)
+{
+ split_point_primitive(pointcloud, NULL, ref.prim_index(), 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);
+ }
+ }
+ }
+ else if (geom->geometry_type == Geometry::POINTCLOUD) {
+ PointCloud *pointcloud = static_cast<PointCloud *>(geom);
+ for (int point_idx = 0; point_idx < pointcloud->num_points(); ++point_idx) {
+ split_point_primitive(
+ pointcloud, &object->get_tfm(), point_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_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_CURVE) {
+ Hair *hair = static_cast<Hair *>(ob->get_geometry());
+ split_curve_reference(ref, hair, dim, pos, left_bounds, right_bounds);
+ }
+ else if (ref.prim_type() & PRIMITIVE_POINT) {
+ PointCloud *pointcloud = static_cast<PointCloud *>(ob->get_geometry());
+ split_point_reference(ref, pointcloud, 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..92953c40040
--- /dev/null
+++ b/intern/cycles/bvh/split.h
@@ -0,0 +1,254 @@
+/*
+ * 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;
+class PointCloud;
+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);
+ void split_point_primitive(const PointCloud *pointcloud,
+ const Transform *tfm,
+ int prim_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_point_reference(const BVHReference &ref,
+ const PointCloud *pointcloud,
+ 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..a8db6efb597
--- /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) && !(type & PRIMITIVE_MOTION)) {
+ 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) && !(type & PRIMITIVE_MOTION)) {
+ 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/cmake/external_libs.cmake b/intern/cycles/cmake/external_libs.cmake
index b966edd4298..f46d18a4926 100644
--- a/intern/cycles/cmake/external_libs.cmake
+++ b/intern/cycles/cmake/external_libs.cmake
@@ -521,7 +521,7 @@ endif()
if(WITH_CYCLES_CUDA_BINARIES OR NOT WITH_CUDA_DYNLOAD)
find_package(CUDA) # Try to auto locate CUDA toolkit
if(CUDA_FOUND)
- message(STATUS "CUDA nvcc = ${CUDA_NVCC_EXECUTABLE}")
+ message(STATUS "Found CUDA ${CUDA_NVCC_EXECUTABLE} (${CUDA_VERSION})")
else()
message(STATUS "CUDA compiler not found, disabling WITH_CYCLES_CUDA_BINARIES")
set(WITH_CYCLES_CUDA_BINARIES OFF)
@@ -537,8 +537,37 @@ endif()
# HIP
###########################################################################
+if(WITH_CYCLES_HIP_BINARIES AND WITH_CYCLES_DEVICE_HIP)
+ find_package(HIP)
+ if(HIP_FOUND)
+ message(STATUS "Found HIP ${HIP_HIPCC_EXECUTABLE} (${HIP_VERSION})")
+ else()
+ message(STATUS "HIP compiler not found, disabling WITH_CYCLES_HIP_BINARIES")
+ set(WITH_CYCLES_HIP_BINARIES OFF)
+ endif()
+endif()
+
if(NOT WITH_HIP_DYNLOAD)
set(WITH_HIP_DYNLOAD ON)
endif()
+###########################################################################
+# Metal
+###########################################################################
+
+if(WITH_CYCLES_DEVICE_METAL)
+ find_library(METAL_LIBRARY Metal)
+
+ # This file was added in the 12.0 SDK, use it as a way to detect the version.
+ if (METAL_LIBRARY AND NOT EXISTS "${METAL_LIBRARY}/Headers/MTLFunctionStitching.h")
+ message(STATUS "Metal version too old, must be SDK 12.0 or newer, disabling WITH_CYCLES_DEVICE_METAL")
+ set(WITH_CYCLES_DEVICE_METAL OFF)
+ elseif (NOT METAL_LIBRARY)
+ message(STATUS "Metal not found, disabling WITH_CYCLES_DEVICE_METAL")
+ set(WITH_CYCLES_DEVICE_METAL OFF)
+ else()
+ message(STATUS "Found Metal: ${METAL_LIBRARY}")
+ endif()
+endif()
+
unset(_cycles_lib_dir)
diff --git a/intern/cycles/cmake/macros.cmake b/intern/cycles/cmake/macros.cmake
index a470fb9c574..5619f7bab72 100644
--- a/intern/cycles/cmake/macros.cmake
+++ b/intern/cycles/cmake/macros.cmake
@@ -84,39 +84,6 @@ macro(cycles_add_library target library_deps)
cycles_set_solution_folder(${target})
endmacro()
-# Cycles library dependencies common to all executables
-
-function(cycles_link_directories)
- if(APPLE)
- # APPLE plaform uses full paths for linking libraries, and avoids link_directories.
- return()
- endif()
-
- if(WITH_OPENCOLORIO)
- link_directories(${OPENCOLORIO_LIBPATH})
- endif()
- if(WITH_OPENVDB)
- link_directories(${OPENVDB_LIBPATH} ${BLOSC_LIBPATH})
- endif()
- if(WITH_OPENSUBDIV)
- link_directories(${OPENSUBDIV_LIBPATH})
- endif()
- if(WITH_OPENIMAGEDENOISE)
- link_directories(${OPENIMAGEDENOISE_LIBPATH})
- endif()
-
- link_directories(
- ${OPENIMAGEIO_LIBPATH}
- ${BOOST_LIBPATH}
- ${PNG_LIBPATH}
- ${JPEG_LIBPATH}
- ${ZLIB_LIBPATH}
- ${TIFF_LIBPATH}
- ${OPENEXR_LIBPATH}
- ${OPENJPEG_LIBPATH}
- )
-endfunction()
-
macro(cycles_target_link_libraries target)
if(WITH_CYCLES_LOGGING)
target_link_libraries(${target} ${GLOG_LIBRARIES} ${GFLAGS_LIBRARIES})
@@ -168,12 +135,6 @@ macro(cycles_target_link_libraries target)
target_link_libraries(${target} extern_hipew)
endif()
- if(CYCLES_STANDALONE_REPOSITORY)
- target_link_libraries(${target} extern_numaapi)
- else()
- target_link_libraries(${target} bf_intern_numaapi)
- endif()
-
if(UNIX AND NOT APPLE)
if(CYCLES_STANDALONE_REPOSITORY)
target_link_libraries(${target} extern_libc_compat)
diff --git a/intern/cycles/device/CMakeLists.txt b/intern/cycles/device/CMakeLists.txt
index 6d33a6f107f..7f1e9ff3d0f 100644
--- a/intern/cycles/device/CMakeLists.txt
+++ b/intern/cycles/device/CMakeLists.txt
@@ -43,13 +43,13 @@ if(WITH_CYCLES_DEVICE_HIP AND WITH_HIP_DYNLOAD)
add_definitions(-DWITH_HIP_DYNLOAD)
endif()
-set(SRC
+set(SRC_BASE
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
@@ -104,6 +104,21 @@ set(SRC_MULTI
multi/device.h
)
+set(SRC_METAL
+ metal/bvh.mm
+ metal/bvh.h
+ metal/device.mm
+ metal/device.h
+ metal/device_impl.mm
+ metal/device_impl.h
+ metal/kernel.mm
+ metal/kernel.h
+ metal/queue.mm
+ metal/queue.h
+ metal/util.mm
+ metal/util.h
+)
+
set(SRC_OPTIX
optix/device.cpp
optix/device.h
@@ -116,11 +131,22 @@ 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(SRC
+ ${SRC_BASE}
+ ${SRC_CPU}
+ ${SRC_CUDA}
+ ${SRC_HIP}
+ ${SRC_DUMMY}
+ ${SRC_MULTI}
+ ${SRC_OPTIX}
+ ${SRC_HEADERS}
)
set(LIB
@@ -158,8 +184,14 @@ endif()
if(WITH_CYCLES_DEVICE_OPTIX)
add_definitions(-DWITH_OPTIX)
endif()
-if(WITH_CYCLES_DEVICE_MULTI)
- add_definitions(-DWITH_MULTI)
+if(WITH_CYCLES_DEVICE_METAL)
+ list(APPEND LIB
+ ${METAL_LIBRARY}
+ )
+ add_definitions(-DWITH_METAL)
+ list(APPEND SRC
+ ${SRC_METAL}
+ )
endif()
if(WITH_OPENIMAGEDENOISE)
@@ -171,20 +203,12 @@ endif()
include_directories(${INC})
include_directories(SYSTEM ${INC_SYS})
-cycles_add_library(cycles_device "${LIB}"
- ${SRC}
- ${SRC_CPU}
- ${SRC_CUDA}
- ${SRC_HIP}
- ${SRC_DUMMY}
- ${SRC_MULTI}
- ${SRC_OPTIX}
- ${SRC_HEADERS}
-)
+cycles_add_library(cycles_device "${LIB}" ${SRC})
source_group("cpu" FILES ${SRC_CPU})
source_group("cuda" FILES ${SRC_CUDA})
source_group("dummy" FILES ${SRC_DUMMY})
source_group("multi" FILES ${SRC_MULTI})
+source_group("metal" FILES ${SRC_METAL})
source_group("optix" FILES ${SRC_OPTIX})
source_group("common" FILES ${SRC} ${SRC_HEADERS})
diff --git a/intern/cycles/device/cpu/device.cpp b/intern/cycles/device/cpu/device.cpp
index 68ca8e8bb22..5aabed8702a 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
@@ -38,7 +38,6 @@ void device_cpu_info(vector<DeviceInfo> &devices)
info.id = "CPU";
info.num = 0;
info.has_osl = true;
- info.has_half_images = true;
info.has_nanovdb = true;
info.has_profiling = true;
if (openimagedenoise_supported()) {
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..0ca24c241f0 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 "bvh/embree.h"
-#include "render/buffers.h"
+#include "session/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 "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
@@ -68,11 +68,11 @@ CPUDevice::CPUDevice(const DeviceInfo &info_, Stats &stats_, Profiler &profiler_
{
/* Pick any kernel, all of them are supposed to have same level of microarchitecture
* optimization. */
- VLOG(1) << "Will be using " << kernels.integrator_init_from_camera.get_uarch_name()
- << " kernels.";
+ VLOG(1) << "Using " << get_cpu_kernels().integrator_init_from_camera.get_uarch_name()
+ << " CPU kernels.";
if (info.cpu_threads == 0) {
- info.cpu_threads = TaskScheduler::num_threads();
+ info.cpu_threads = TaskScheduler::max_concurrency();
}
#ifdef WITH_OSL
@@ -93,11 +93,6 @@ CPUDevice::~CPUDevice()
texture_info.free();
}
-bool CPUDevice::show_samples() const
-{
- return (info.cpu_threads == 1);
-}
-
BVHLayoutMask CPUDevice::get_bvh_layout_mask() const
{
BVHLayoutMask bvh_layout_mask = BVH_LAYOUT_BVH2;
@@ -134,8 +129,7 @@ void CPUDevice::mem_alloc(device_memory &mem)
<< string_human_readable_size(mem.memory_size()) << ")";
}
- if (mem.type == MEM_DEVICE_ONLY) {
- assert(!mem.host_pointer);
+ if (mem.type == MEM_DEVICE_ONLY || !mem.host_pointer) {
size_t alignment = MIN_ALIGNMENT_CPU_DATA_TYPES;
void *data = util_aligned_malloc(mem.memory_size(), alignment);
mem.device_pointer = (device_ptr)data;
@@ -194,7 +188,7 @@ void CPUDevice::mem_free(device_memory &mem)
tex_free((device_texture &)mem);
}
else if (mem.device_pointer) {
- if (mem.type == MEM_DEVICE_ONLY) {
+ if (mem.type == MEM_DEVICE_ONLY || !mem.host_pointer) {
util_aligned_free((void *)mem.device_pointer);
}
mem.device_pointer = 0;
@@ -279,7 +273,8 @@ void CPUDevice::build_bvh(BVH *bvh, Progress &progress, bool refit)
{
#ifdef WITH_EMBREE
if (bvh->params.bvh_layout == BVH_LAYOUT_EMBREE ||
- bvh->params.bvh_layout == BVH_LAYOUT_MULTI_OPTIX_EMBREE) {
+ bvh->params.bvh_layout == BVH_LAYOUT_MULTI_OPTIX_EMBREE ||
+ bvh->params.bvh_layout == BVH_LAYOUT_MULTI_METAL_EMBREE) {
BVHEmbree *const bvh_embree = static_cast<BVHEmbree *>(bvh);
if (refit) {
bvh_embree->refit(progress);
@@ -297,11 +292,6 @@ void CPUDevice::build_bvh(BVH *bvh, Progress &progress, bool refit)
Device::build_bvh(bvh, progress, refit);
}
-const CPUKernels *CPUDevice::get_cpu_kernels() const
-{
- return &kernels;
-}
-
void CPUDevice::get_cpu_kernel_thread_globals(
vector<CPUKernelThreadGlobals> &kernel_thread_globals)
{
diff --git a/intern/cycles/device/cpu/device_impl.h b/intern/cycles/device/cpu/device_impl.h
index 371d2258104..6f9452a6378 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,22 +29,22 @@
#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
class CPUDevice : public Device {
public:
- KernelGlobals kernel_globals;
+ KernelGlobalsCPU kernel_globals;
device_vector<TextureInfo> texture_info;
bool need_texture_info;
@@ -57,13 +57,9 @@ class CPUDevice : public Device {
RTCDevice embree_device;
#endif
- CPUKernels kernels;
-
CPUDevice(const DeviceInfo &info_, Stats &stats_, Profiler &profiler_);
~CPUDevice();
- virtual bool show_samples() const override;
-
virtual BVHLayoutMask get_bvh_layout_mask() const override;
/* Returns true if the texture info was copied to the device (meaning, some more
@@ -90,7 +86,6 @@ class CPUDevice : public Device {
void build_bvh(BVH *bvh, Progress &progress, bool refit) override;
- virtual const CPUKernels *get_cpu_kernels() const override;
virtual void get_cpu_kernel_thread_globals(
vector<CPUKernelThreadGlobals> &kernel_thread_globals) override;
virtual void *get_cpu_osl_memory() override;
diff --git a/intern/cycles/device/cpu/kernel.cpp b/intern/cycles/device/cpu/kernel.cpp
index 91282390e27..91c472d41e8 100644
--- a/intern/cycles/device/cpu/kernel.cpp
+++ b/intern/cycles/device/cpu/kernel.cpp
@@ -26,6 +26,9 @@ CCL_NAMESPACE_BEGIN
KERNEL_NAME_EVAL(cpu_avx, name), KERNEL_NAME_EVAL(cpu_avx2, name)
#define REGISTER_KERNEL(name) name(KERNEL_FUNCTIONS(name))
+#define REGISTER_KERNEL_FILM_CONVERT(name) \
+ film_convert_##name(KERNEL_FUNCTIONS(film_convert_##name)), \
+ film_convert_half_rgba_##name(KERNEL_FUNCTIONS(film_convert_half_rgba_##name))
CPUKernels::CPUKernels()
: /* Integrator. */
@@ -44,18 +47,31 @@ CPUKernels::CPUKernels()
/* Shader evaluation. */
REGISTER_KERNEL(shader_eval_displace),
REGISTER_KERNEL(shader_eval_background),
+ REGISTER_KERNEL(shader_eval_curve_shadow_transparency),
/* Adaptive sampling. */
REGISTER_KERNEL(adaptive_sampling_convergence_check),
REGISTER_KERNEL(adaptive_sampling_filter_x),
REGISTER_KERNEL(adaptive_sampling_filter_y),
/* Cryptomatte. */
REGISTER_KERNEL(cryptomatte_postprocess),
- /* Bake. */
- REGISTER_KERNEL(bake)
+ /* Film Convert. */
+ REGISTER_KERNEL_FILM_CONVERT(depth),
+ REGISTER_KERNEL_FILM_CONVERT(mist),
+ REGISTER_KERNEL_FILM_CONVERT(sample_count),
+ REGISTER_KERNEL_FILM_CONVERT(float),
+ REGISTER_KERNEL_FILM_CONVERT(light_path),
+ REGISTER_KERNEL_FILM_CONVERT(float3),
+ REGISTER_KERNEL_FILM_CONVERT(motion),
+ REGISTER_KERNEL_FILM_CONVERT(cryptomatte),
+ REGISTER_KERNEL_FILM_CONVERT(shadow_catcher),
+ REGISTER_KERNEL_FILM_CONVERT(shadow_catcher_matte_with_shadow),
+ REGISTER_KERNEL_FILM_CONVERT(combined),
+ REGISTER_KERNEL_FILM_CONVERT(float4)
{
}
#undef REGISTER_KERNEL
+#undef REGISTER_KERNEL_FILM_CONVERT
#undef KERNEL_FUNCTIONS
CCL_NAMESPACE_END
diff --git a/intern/cycles/device/cpu/kernel.h b/intern/cycles/device/cpu/kernel.h
index 54b18308544..2d1de975c2b 100644
--- a/intern/cycles/device/cpu/kernel.h
+++ b/intern/cycles/device/cpu/kernel.h
@@ -17,11 +17,13 @@
#pragma once
#include "device/cpu/kernel_function.h"
-#include "util/util_types.h"
+#include "util/half.h"
+#include "util/types.h"
CCL_NAMESPACE_BEGIN
-struct KernelGlobals;
+struct KernelGlobalsCPU;
+struct KernelFilmConvert;
struct IntegratorStateCPU;
struct TileInfo;
@@ -30,17 +32,17 @@ class CPUKernels {
/* Integrator. */
using IntegratorFunction =
- CPUKernelFunction<void (*)(const KernelGlobals *kg, IntegratorStateCPU *state)>;
+ CPUKernelFunction<void (*)(const KernelGlobalsCPU *kg, IntegratorStateCPU *state)>;
using IntegratorShadeFunction = CPUKernelFunction<void (*)(
- const KernelGlobals *kg, IntegratorStateCPU *state, ccl_global float *render_buffer)>;
- using IntegratorInitFunction = CPUKernelFunction<bool (*)(const KernelGlobals *kg,
+ const KernelGlobalsCPU *kg, IntegratorStateCPU *state, ccl_global float *render_buffer)>;
+ using IntegratorInitFunction = CPUKernelFunction<bool (*)(const KernelGlobalsCPU *kg,
IntegratorStateCPU *state,
KernelWorkTile *tile,
ccl_global float *render_buffer)>;
IntegratorInitFunction integrator_init_from_camera;
IntegratorInitFunction integrator_init_from_bake;
- IntegratorFunction integrator_intersect_closest;
+ IntegratorShadeFunction integrator_intersect_closest;
IntegratorFunction integrator_intersect_shadow;
IntegratorFunction integrator_intersect_subsurface;
IntegratorFunction integrator_intersect_volume_stack;
@@ -54,15 +56,16 @@ class CPUKernels {
/* Shader evaluation. */
using ShaderEvalFunction = CPUKernelFunction<void (*)(
- const KernelGlobals *kg, const KernelShaderEvalInput *, float4 *, const int)>;
+ const KernelGlobalsCPU *kg, const KernelShaderEvalInput *, float *, const int)>;
ShaderEvalFunction shader_eval_displace;
ShaderEvalFunction shader_eval_background;
+ ShaderEvalFunction shader_eval_curve_shadow_transparency;
/* Adaptive stopping. */
using AdaptiveSamplingConvergenceCheckFunction =
- CPUKernelFunction<bool (*)(const KernelGlobals *kg,
+ CPUKernelFunction<bool (*)(const KernelGlobalsCPU *kg,
ccl_global float *render_buffer,
int x,
int y,
@@ -72,7 +75,7 @@ class CPUKernels {
int stride)>;
using AdaptiveSamplingFilterXFunction =
- CPUKernelFunction<void (*)(const KernelGlobals *kg,
+ CPUKernelFunction<void (*)(const KernelGlobalsCPU *kg,
ccl_global float *render_buffer,
int y,
int start_x,
@@ -81,7 +84,7 @@ class CPUKernels {
int stride)>;
using AdaptiveSamplingFilterYFunction =
- CPUKernelFunction<void (*)(const KernelGlobals *kg,
+ CPUKernelFunction<void (*)(const KernelGlobalsCPU *kg,
ccl_global float *render_buffer,
int x,
int start_y,
@@ -97,13 +100,44 @@ class CPUKernels {
/* Cryptomatte. */
using CryptomattePostprocessFunction = CPUKernelFunction<void (*)(
- const KernelGlobals *kg, ccl_global float *render_buffer, int pixel_index)>;
+ const KernelGlobalsCPU *kg, ccl_global float *render_buffer, int pixel_index)>;
CryptomattePostprocessFunction cryptomatte_postprocess;
- /* Bake. */
-
- CPUKernelFunction<void (*)(const KernelGlobals *, float *, int, int, int, int, int)> bake;
+ /* Film Convert. */
+ using FilmConvertFunction = CPUKernelFunction<void (*)(const KernelFilmConvert *kfilm_convert,
+ const float *buffer,
+ float *pixel,
+ const int width,
+ const int buffer_stride,
+ const int pixel_stride)>;
+ using FilmConvertHalfRGBAFunction =
+ CPUKernelFunction<void (*)(const KernelFilmConvert *kfilm_convert,
+ const float *buffer,
+ half4 *pixel,
+ const int width,
+ const int buffer_stride)>;
+
+#define KERNEL_FILM_CONVERT_FUNCTION(name) \
+ FilmConvertFunction film_convert_##name; \
+ FilmConvertHalfRGBAFunction film_convert_half_rgba_##name;
+
+ KERNEL_FILM_CONVERT_FUNCTION(depth)
+ KERNEL_FILM_CONVERT_FUNCTION(mist)
+ KERNEL_FILM_CONVERT_FUNCTION(sample_count)
+ KERNEL_FILM_CONVERT_FUNCTION(float)
+
+ KERNEL_FILM_CONVERT_FUNCTION(light_path)
+ KERNEL_FILM_CONVERT_FUNCTION(float3)
+
+ KERNEL_FILM_CONVERT_FUNCTION(motion)
+ KERNEL_FILM_CONVERT_FUNCTION(cryptomatte)
+ KERNEL_FILM_CONVERT_FUNCTION(shadow_catcher)
+ KERNEL_FILM_CONVERT_FUNCTION(shadow_catcher_matte_with_shadow)
+ KERNEL_FILM_CONVERT_FUNCTION(combined)
+ KERNEL_FILM_CONVERT_FUNCTION(float4)
+
+#undef KERNEL_FILM_CONVERT_FUNCTION
CPUKernels();
};
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 988b00cd1f0..739b6460318 100644
--- a/intern/cycles/device/cpu/kernel_thread_globals.cpp
+++ b/intern/cycles/device/cpu/kernel_thread_globals.cpp
@@ -17,18 +17,18 @@
#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
-CPUKernelThreadGlobals::CPUKernelThreadGlobals(const KernelGlobals &kernel_globals,
+CPUKernelThreadGlobals::CPUKernelThreadGlobals(const KernelGlobalsCPU &kernel_globals,
void *osl_globals_memory,
Profiler &cpu_profiler)
- : KernelGlobals(kernel_globals), cpu_profiler_(cpu_profiler)
+ : KernelGlobalsCPU(kernel_globals), cpu_profiler_(cpu_profiler)
{
reset_runtime_memory();
@@ -40,7 +40,7 @@ CPUKernelThreadGlobals::CPUKernelThreadGlobals(const KernelGlobals &kernel_globa
}
CPUKernelThreadGlobals::CPUKernelThreadGlobals(CPUKernelThreadGlobals &&other) noexcept
- : KernelGlobals(std::move(other)), cpu_profiler_(other.cpu_profiler_)
+ : KernelGlobalsCPU(std::move(other)), cpu_profiler_(other.cpu_profiler_)
{
other.reset_runtime_memory();
}
@@ -58,7 +58,7 @@ CPUKernelThreadGlobals &CPUKernelThreadGlobals::operator=(CPUKernelThreadGlobals
return *this;
}
- *static_cast<KernelGlobals *>(this) = *static_cast<KernelGlobals *>(&other);
+ *static_cast<KernelGlobalsCPU *>(this) = *static_cast<KernelGlobalsCPU *>(&other);
other.reset_runtime_memory();
diff --git a/intern/cycles/device/cpu/kernel_thread_globals.h b/intern/cycles/device/cpu/kernel_thread_globals.h
index d005c3bb56c..5aeeaf678d0 100644
--- a/intern/cycles/device/cpu/kernel_thread_globals.h
+++ b/intern/cycles/device/cpu/kernel_thread_globals.h
@@ -23,17 +23,17 @@ CCL_NAMESPACE_BEGIN
class Profiler;
-/* A special class which extends memory ownership of the `KernelGlobals` decoupling any resource
+/* A special class which extends memory ownership of the `KernelGlobalsCPU` decoupling any resource
* which is not thread-safe for access. Every worker thread which needs to operate on
- * `KernelGlobals` needs to initialize its own copy of this object.
+ * `KernelGlobalsCPU` needs to initialize its own copy of this object.
*
* NOTE: Only minimal subset of objects are copied: `KernelData` is never copied. This means that
* there is no unnecessary data duplication happening when using this object. */
-class CPUKernelThreadGlobals : public KernelGlobals {
+class CPUKernelThreadGlobals : public KernelGlobalsCPU {
public:
/* TODO(sergey): Would be nice to have properly typed OSLGlobals even in the case when building
* without OSL support. Will avoid need to those unnamed pointers and casts. */
- CPUKernelThreadGlobals(const KernelGlobals &kernel_globals,
+ CPUKernelThreadGlobals(const KernelGlobalsCPU &kernel_globals,
void *osl_globals_memory,
Profiler &cpu_profiler);
diff --git a/intern/cycles/device/cuda/device.cpp b/intern/cycles/device/cuda/device.cpp
index 84becd6d081..0d9e6c72466 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
@@ -144,7 +144,6 @@ void device_cuda_info(vector<DeviceInfo> &devices)
info.description = string(name);
info.num = num;
- info.has_half_images = (major >= 3);
info.has_nanovdb = true;
info.denoisers = 0;
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 5e1a63c04df..8d022040414 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
@@ -48,12 +46,6 @@ bool CUDADevice::have_precompiled_kernels()
return path_exists(cubins_path);
}
-bool CUDADevice::show_samples() const
-{
- /* The CUDADevice only processes one tile at a time, so showing samples is fine. */
- return true;
-}
-
BVHLayoutMask CUDADevice::get_bvh_layout_mask() const
{
return BVH_LAYOUT_BVH2;
@@ -244,6 +236,10 @@ string CUDADevice::compile_kernel_get_common_cflags(const uint kernel_features)
cflags += " -DWITH_NANOVDB";
# endif
+# ifdef WITH_CYCLES_DEBUG
+ cflags += " -DWITH_CYCLES_DEBUG";
+# endif
+
return cflags;
}
@@ -380,7 +376,9 @@ string CUDADevice::compile_kernel(const uint kernel_features,
cubin.c_str(),
common_cflags.c_str());
- printf("Compiling CUDA kernel ...\n%s\n", command.c_str());
+ printf("Compiling %sCUDA kernel ...\n%s\n",
+ (use_adaptive_compilation()) ? "adaptive " : "",
+ command.c_str());
# ifdef _WIN32
command = "call " + command;
@@ -407,13 +405,15 @@ string CUDADevice::compile_kernel(const uint kernel_features,
bool CUDADevice::load_kernels(const uint kernel_features)
{
- /* TODO(sergey): Support kernels re-load for CUDA devices.
+ /* TODO(sergey): Support kernels re-load for CUDA devices adaptive compile.
*
* Currently re-loading kernel will invalidate memory pointers,
* causing problems in cuCtxSynchronize.
*/
if (cuModule) {
- VLOG(1) << "Skipping kernel reload, not currently supported.";
+ if (use_adaptive_compilation()) {
+ VLOG(1) << "Skipping CUDA kernel reload for adaptive compilation, not currently supported.";
+ }
return true;
}
@@ -454,7 +454,7 @@ bool CUDADevice::load_kernels(const uint kernel_features)
return (result == CUDA_SUCCESS);
}
-void CUDADevice::reserve_local_memory(const uint /* kernel_features */)
+void CUDADevice::reserve_local_memory(const uint kernel_features)
{
/* Together with CU_CTX_LMEM_RESIZE_TO_MAX, this reserves local memory
* needed for kernel launches, so that we can reliably figure out when
@@ -468,17 +468,19 @@ void CUDADevice::reserve_local_memory(const uint /* kernel_features */)
{
/* Use the biggest kernel for estimation. */
- const DeviceKernel test_kernel = DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE;
+ const DeviceKernel test_kernel = (kernel_features & KERNEL_FEATURE_NODE_RAYTRACE) ?
+ DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE :
+ DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE;
/* Launch kernel, using just 1 block appears sufficient to reserve memory for all
* multiprocessors. It would be good to do this in parallel for the multi GPU case
* still to make it faster. */
CUDADeviceQueue queue(this);
- void *d_path_index = nullptr;
- void *d_render_buffer = nullptr;
+ device_ptr d_path_index = 0;
+ device_ptr d_render_buffer = 0;
int d_work_size = 0;
- void *args[] = {&d_path_index, &d_render_buffer, &d_work_size};
+ DeviceKernelArguments args(&d_path_index, &d_render_buffer, &d_work_size);
queue.init_execution();
queue.enqueue(test_kernel, 1, args);
@@ -676,7 +678,7 @@ CUDADevice::CUDAMem *CUDADevice::generic_alloc(device_memory &mem, size_t pitch_
void *shared_pointer = 0;
- if (mem_alloc_result != CUDA_SUCCESS && can_map_host) {
+ if (mem_alloc_result != CUDA_SUCCESS && can_map_host && mem.type != MEM_DEVICE_ONLY) {
if (mem.shared_pointer) {
/* Another device already allocated host memory. */
mem_alloc_result = CUDA_SUCCESS;
@@ -699,8 +701,14 @@ CUDADevice::CUDAMem *CUDADevice::generic_alloc(device_memory &mem, size_t pitch_
}
if (mem_alloc_result != CUDA_SUCCESS) {
- status = " failed, out of device and host memory";
- set_error("System is out of GPU and shared host memory");
+ if (mem.type == MEM_DEVICE_ONLY) {
+ status = " failed, out of device memory";
+ set_error("System is out of GPU memory");
+ }
+ else {
+ status = " failed, out of device and host memory";
+ set_error("System is out of GPU and shared host memory");
+ }
}
if (mem.name) {
@@ -773,6 +781,7 @@ void CUDADevice::generic_free(device_memory &mem)
if (mem.device_pointer) {
CUDAContextScope scope(this);
thread_scoped_lock lock(cuda_mem_map_mutex);
+ DCHECK(cuda_mem_map.find(&mem) != cuda_mem_map.end());
const CUDAMem &cmem = cuda_mem_map[&mem];
/* If cmem.use_mapped_host is true, reference counting is used
@@ -927,7 +936,6 @@ void CUDADevice::tex_alloc(device_texture &mem)
{
CUDAContextScope scope(this);
- /* General variables for both architectures */
string bind_name = mem.name;
size_t dsize = datatype_size(mem.data_type);
size_t size = mem.memory_size();
@@ -1090,7 +1098,6 @@ void CUDADevice::tex_alloc(device_texture &mem)
if (mem.info.data_type != IMAGE_DATA_TYPE_NANOVDB_FLOAT &&
mem.info.data_type != IMAGE_DATA_TYPE_NANOVDB_FLOAT3) {
- /* Kepler+, bindless textures. */
CUDA_RESOURCE_DESC resDesc;
memset(&resDesc, 0, sizeof(resDesc));
@@ -1141,6 +1148,7 @@ void CUDADevice::tex_free(device_texture &mem)
if (mem.device_pointer) {
CUDAContextScope scope(this);
thread_scoped_lock lock(cuda_mem_map_mutex);
+ DCHECK(cuda_mem_map.find(&mem) != cuda_mem_map.end());
const CUDAMem &cmem = cuda_mem_map[&mem];
if (cmem.texobject) {
diff --git a/intern/cycles/device/cuda/device_impl.h b/intern/cycles/device/cuda/device_impl.h
index c0316d18ba0..4c357d0b5ab 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"
@@ -76,8 +76,6 @@ class CUDADevice : public Device {
static bool have_precompiled_kernels();
- virtual bool show_samples() const override;
-
virtual BVHLayoutMask get_bvh_layout_mask() const override;
void set_error(const string &error) override;
diff --git a/intern/cycles/device/cuda/graphics_interop.cpp b/intern/cycles/device/cuda/graphics_interop.cpp
index e8ca8b90eae..c75d7957460 100644
--- a/intern/cycles/device/cuda/graphics_interop.cpp
+++ b/intern/cycles/device/cuda/graphics_interop.cpp
@@ -37,15 +37,18 @@ CUDADeviceGraphicsInterop::~CUDADeviceGraphicsInterop()
}
}
-void CUDADeviceGraphicsInterop::set_destination(
- const DeviceGraphicsInteropDestination &destination)
+void CUDADeviceGraphicsInterop::set_display_interop(
+ const DisplayDriver::GraphicsInterop &display_interop)
{
- const int64_t new_buffer_area = int64_t(destination.buffer_width) * destination.buffer_height;
+ const int64_t new_buffer_area = int64_t(display_interop.buffer_width) *
+ display_interop.buffer_height;
- need_clear_ = destination.need_clear;
+ need_clear_ = display_interop.need_clear;
- if (opengl_pbo_id_ == destination.opengl_pbo_id && buffer_area_ == new_buffer_area) {
- return;
+ if (!display_interop.need_recreate) {
+ if (opengl_pbo_id_ == display_interop.opengl_pbo_id && buffer_area_ == new_buffer_area) {
+ return;
+ }
}
CUDAContextScope scope(device_);
@@ -55,12 +58,12 @@ void CUDADeviceGraphicsInterop::set_destination(
}
const CUresult result = cuGraphicsGLRegisterBuffer(
- &cu_graphics_resource_, destination.opengl_pbo_id, CU_GRAPHICS_MAP_RESOURCE_FLAGS_NONE);
+ &cu_graphics_resource_, display_interop.opengl_pbo_id, CU_GRAPHICS_MAP_RESOURCE_FLAGS_NONE);
if (result != CUDA_SUCCESS) {
LOG(ERROR) << "Error registering OpenGL buffer: " << cuewErrorString(result);
}
- opengl_pbo_id_ = destination.opengl_pbo_id;
+ opengl_pbo_id_ = display_interop.opengl_pbo_id;
buffer_area_ = new_buffer_area;
}
diff --git a/intern/cycles/device/cuda/graphics_interop.h b/intern/cycles/device/cuda/graphics_interop.h
index 8a70c8aa71d..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"
@@ -41,7 +41,7 @@ class CUDADeviceGraphicsInterop : public DeviceGraphicsInterop {
CUDADeviceGraphicsInterop &operator=(const CUDADeviceGraphicsInterop &other) = delete;
CUDADeviceGraphicsInterop &operator=(CUDADeviceGraphicsInterop &&other) = delete;
- virtual void set_destination(const DeviceGraphicsInteropDestination &destination) override;
+ virtual void set_display_interop(const DisplayDriver::GraphicsInterop &display_interop) override;
virtual device_ptr map() override;
virtual void unmap() override;
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.cpp b/intern/cycles/device/cuda/queue.cpp
index 1149a835b14..ca57882adbf 100644
--- a/intern/cycles/device/cuda/queue.cpp
+++ b/intern/cycles/device/cuda/queue.cpp
@@ -41,13 +41,19 @@ CUDADeviceQueue::~CUDADeviceQueue()
int CUDADeviceQueue::num_concurrent_states(const size_t state_size) const
{
- int num_states = max(cuda_device_->get_num_multiprocessors() *
- cuda_device_->get_max_num_threads_per_multiprocessor() * 16,
- 1048576);
+ const int max_num_threads = cuda_device_->get_num_multiprocessors() *
+ cuda_device_->get_max_num_threads_per_multiprocessor();
+ int num_states = max(max_num_threads, 65536) * 16;
const char *factor_str = getenv("CYCLES_CONCURRENT_STATES_FACTOR");
if (factor_str) {
- num_states = max((int)(num_states * atof(factor_str)), 1024);
+ const float factor = (float)atof(factor_str);
+ if (factor != 0.0f) {
+ num_states = max((int)(num_states * factor), 1024);
+ }
+ else {
+ VLOG(3) << "CYCLES_CONCURRENT_STATES_FACTOR evaluated to 0";
+ }
}
VLOG(3) << "GPU queue concurrent states: " << num_states << ", using up to "
@@ -83,7 +89,9 @@ bool CUDADeviceQueue::kernel_available(DeviceKernel kernel) const
return cuda_device_->kernels.available(kernel);
}
-bool CUDADeviceQueue::enqueue(DeviceKernel kernel, const int work_size, void *args[])
+bool CUDADeviceQueue::enqueue(DeviceKernel kernel,
+ const int work_size,
+ DeviceKernelArguments const &args)
{
if (cuda_device_->have_error()) {
return false;
@@ -107,6 +115,8 @@ bool CUDADeviceQueue::enqueue(DeviceKernel kernel, const int work_size, void *ar
case DEVICE_KERNEL_INTEGRATOR_TERMINATED_PATHS_ARRAY:
case DEVICE_KERNEL_INTEGRATOR_SORTED_PATHS_ARRAY:
case DEVICE_KERNEL_INTEGRATOR_COMPACT_PATHS_ARRAY:
+ case DEVICE_KERNEL_INTEGRATOR_TERMINATED_SHADOW_PATHS_ARRAY:
+ case DEVICE_KERNEL_INTEGRATOR_COMPACT_SHADOW_PATHS_ARRAY:
/* See parall_active_index.h for why this amount of shared memory is needed. */
shared_mem_bytes = (num_threads_per_block + 1) * sizeof(int);
break;
@@ -125,7 +135,7 @@ bool CUDADeviceQueue::enqueue(DeviceKernel kernel, const int work_size, void *ar
1,
shared_mem_bytes,
cuda_stream_,
- args,
+ const_cast<void **>(args.values),
0),
"enqueue");
diff --git a/intern/cycles/device/cuda/queue.h b/intern/cycles/device/cuda/queue.h
index 4d1995ed69e..0836af12098 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"
@@ -42,7 +42,9 @@ class CUDADeviceQueue : public DeviceQueue {
virtual bool kernel_available(DeviceKernel kernel) const override;
- virtual bool enqueue(DeviceKernel kernel, const int work_size, void *args[]) override;
+ virtual bool enqueue(DeviceKernel kernel,
+ const int work_size,
+ DeviceKernelArguments const &args) override;
virtual bool synchronize() override;
diff --git a/intern/cycles/device/denoise.cpp b/intern/cycles/device/denoise.cpp
new file mode 100644
index 00000000000..8ae2bb213e4
--- /dev/null
+++ b/intern/cycles/device/denoise.cpp
@@ -0,0 +1,90 @@
+/*
+ * 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_BOOLEAN(temporally_stable, "Temporally Stable", 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..07868527fc5
--- /dev/null
+++ b/intern/cycles/device/denoise.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.
+ */
+
+#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;
+
+ /* Configure the denoiser to use motion vectors, previous image and a temporally stable model. */
+ bool temporally_stable = false;
+
+ 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 &&
+ temporally_stable == other.temporally_stable && 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..14c97affb76 100644
--- a/intern/cycles/device/device.cpp
+++ b/intern/cycles/device/device.cpp
@@ -20,24 +20,27 @@
#include "bvh/bvh2.h"
#include "device/device.h"
-#include "device/device_queue.h"
+#include "device/queue.h"
#include "device/cpu/device.h"
+#include "device/cpu/kernel.h"
#include "device/cuda/device.h"
#include "device/dummy/device.h"
#include "device/hip/device.h"
+#include "device/metal/device.h"
#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/task.h"
+#include "util/time.h"
+#include "util/types.h"
+#include "util/vector.h"
CCL_NAMESPACE_BEGIN
@@ -48,6 +51,7 @@ vector<DeviceInfo> Device::cuda_devices;
vector<DeviceInfo> Device::optix_devices;
vector<DeviceInfo> Device::cpu_devices;
vector<DeviceInfo> Device::hip_devices;
+vector<DeviceInfo> Device::metal_devices;
uint Device::devices_initialized_mask = 0;
/* Device */
@@ -71,14 +75,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;
@@ -106,6 +108,12 @@ Device *Device::create(const DeviceInfo &info, Stats &stats, Profiler &profiler)
break;
#endif
+#ifdef WITH_METAL
+ case DEVICE_METAL:
+ if (device_metal_init())
+ device = device_metal_create(info, stats, profiler);
+ break;
+#endif
default:
break;
}
@@ -129,6 +137,8 @@ DeviceType Device::type_from_string(const char *name)
return DEVICE_MULTI;
else if (strcmp(name, "HIP") == 0)
return DEVICE_HIP;
+ else if (strcmp(name, "METAL") == 0)
+ return DEVICE_METAL;
return DEVICE_NONE;
}
@@ -145,6 +155,8 @@ string Device::string_from_type(DeviceType type)
return "MULTI";
else if (type == DEVICE_HIP)
return "HIP";
+ else if (type == DEVICE_METAL)
+ return "METAL";
return "";
}
@@ -162,7 +174,9 @@ vector<DeviceType> Device::available_types()
#ifdef WITH_HIP
types.push_back(DEVICE_HIP);
#endif
-
+#ifdef WITH_METAL
+ types.push_back(DEVICE_METAL);
+#endif
return types;
}
@@ -228,6 +242,20 @@ vector<DeviceInfo> Device::available_devices(uint mask)
}
}
+#ifdef WITH_METAL
+ if (mask & DEVICE_MASK_METAL) {
+ if (!(devices_initialized_mask & DEVICE_MASK_METAL)) {
+ if (device_metal_init()) {
+ device_metal_info(metal_devices);
+ }
+ devices_initialized_mask |= DEVICE_MASK_METAL;
+ }
+ foreach (DeviceInfo &info, metal_devices) {
+ devices.push_back(info);
+ }
+ }
+#endif
+
return devices;
}
@@ -267,6 +295,15 @@ string Device::device_capabilities(uint mask)
}
#endif
+#ifdef WITH_METAL
+ if (mask & DEVICE_MASK_METAL) {
+ if (device_metal_init()) {
+ capabilities += "\nMetal device capabilities:\n";
+ capabilities += device_metal_capabilities();
+ }
+ }
+#endif
+
return capabilities;
}
@@ -287,7 +324,6 @@ DeviceInfo Device::get_multi_device(const vector<DeviceInfo> &subdevices,
info.description = "Multi Device";
info.num = 0;
- info.has_half_images = true;
info.has_nanovdb = true;
info.has_osl = true;
info.has_profiling = true;
@@ -298,7 +334,7 @@ DeviceInfo Device::get_multi_device(const vector<DeviceInfo> &subdevices,
/* Ensure CPU device does not slow down GPU. */
if (device.type == DEVICE_CPU && subdevices.size() > 1) {
if (background) {
- int orig_cpu_threads = (threads) ? threads : system_cpu_thread_count();
+ int orig_cpu_threads = (threads) ? threads : TaskScheduler::max_concurrency();
int cpu_threads = max(orig_cpu_threads - (subdevices.size() - 1), 0);
VLOG(1) << "CPU render threads reduced from " << orig_cpu_threads << " to " << cpu_threads
@@ -334,7 +370,6 @@ DeviceInfo Device::get_multi_device(const vector<DeviceInfo> &subdevices,
}
/* Accumulate device info. */
- info.has_half_images &= device.has_half_images;
info.has_nanovdb &= device.has_nanovdb;
info.has_osl &= device.has_osl;
info.has_profiling &= device.has_profiling;
@@ -357,6 +392,7 @@ void Device::free_memory()
optix_devices.free_memory();
hip_devices.free_memory();
cpu_devices.free_memory();
+ metal_devices.free_memory();
}
unique_ptr<DeviceQueue> Device::gpu_queue_create()
@@ -365,10 +401,11 @@ unique_ptr<DeviceQueue> Device::gpu_queue_create()
return nullptr;
}
-const CPUKernels *Device::get_cpu_kernels() const
+const CPUKernels &Device::get_cpu_kernels()
{
- LOG(FATAL) << "Device does not support CPU kernels.";
- return nullptr;
+ /* Initialize CPU kernels once and reuse. */
+ static CPUKernels kernels;
+ return kernels;
}
void Device::get_cpu_kernel_thread_globals(
diff --git a/intern/cycles/device/device.h b/intern/cycles/device/device.h
index c73d74cdccc..c032773ddd0 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
@@ -52,6 +52,7 @@ enum DeviceType {
DEVICE_MULTI,
DEVICE_OPTIX,
DEVICE_HIP,
+ DEVICE_METAL,
DEVICE_DUMMY,
};
@@ -60,6 +61,7 @@ enum DeviceTypeMask {
DEVICE_MASK_CUDA = (1 << DEVICE_CUDA),
DEVICE_MASK_OPTIX = (1 << DEVICE_OPTIX),
DEVICE_MASK_HIP = (1 << DEVICE_HIP),
+ DEVICE_MASK_METAL = (1 << DEVICE_METAL),
DEVICE_MASK_ALL = ~0
};
@@ -73,7 +75,6 @@ class DeviceInfo {
int num;
bool display_device; /* GPU is used as a display device. */
bool has_nanovdb; /* Support NanoVDB volumes. */
- bool has_half_images; /* Support half-float textures. */
bool has_osl; /* Support Open Shading Language. */
bool has_profiling; /* Supports runtime collection of profiling info. */
bool has_peer_memory; /* GPU has P2P access to memory of another GPU. */
@@ -90,7 +91,6 @@ class DeviceInfo {
num = 0;
cpu_threads = 0;
display_device = false;
- has_half_images = false;
has_nanovdb = false;
has_osl = false;
has_profiling = false;
@@ -151,10 +151,6 @@ class Device {
fprintf(stderr, "%s\n", error.c_str());
fflush(stderr);
}
- virtual bool show_samples() const
- {
- return false;
- }
virtual BVHLayoutMask get_bvh_layout_mask() const = 0;
/* statistics */
@@ -180,7 +176,7 @@ class Device {
* These may not be used on GPU or multi-devices. */
/* Get CPU kernel functions for native instruction set. */
- virtual const CPUKernels *get_cpu_kernels() const;
+ static const CPUKernels &get_cpu_kernels();
/* Get kernel globals to pass to kernels. */
virtual void get_cpu_kernel_thread_globals(
vector<CPUKernelThreadGlobals> & /*kernel_thread_globals*/);
@@ -287,6 +283,7 @@ class Device {
static vector<DeviceInfo> optix_devices;
static vector<DeviceInfo> cpu_devices;
static vector<DeviceInfo> hip_devices;
+ static vector<DeviceInfo> metal_devices;
static uint devices_initialized_mask;
};
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 671b1c189d7..00000000000
--- a/intern/cycles/device/device_graphics_interop.h
+++ /dev/null
@@ -1,55 +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 "util/util_types.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Information about interoperability destination.
- * Is provided by the GPUDisplay. */
-class DeviceGraphicsInteropDestination {
- 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 destination before doing partial write to it. */
- bool need_clear = false;
-};
-
-/* 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_destination(const DeviceGraphicsInteropDestination &destination) = 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 ceaddee4756..00000000000
--- a/intern/cycles/device/device_kernel.cpp
+++ /dev/null
@@ -1,157 +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_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";
-
- /* 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..a9c7b1ba841 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
@@ -57,9 +57,16 @@ bool device_hip_init()
}
}
else {
- VLOG(1) << "HIPEW initialization failed: "
- << ((hipew_result == HIPEW_ERROR_ATEXIT_FAILED) ? "Error setting up atexit() handler" :
- "Error opening the library");
+ if (hipew_result == HIPEW_ERROR_ATEXIT_FAILED) {
+ VLOG(1) << "HIPEW initialization failed: Error setting up atexit() handler";
+ }
+ else if (hipew_result == HIPEW_ERROR_OLD_DRIVER) {
+ VLOG(1) << "HIPEW initialization failed: Driver version too old, requires AMD Radeon Pro "
+ "21.Q4 driver or newer";
+ }
+ else {
+ VLOG(1) << "HIPEW initialization failed: Error opening HIP dynamic library";
+ }
}
return result;
@@ -131,9 +138,9 @@ void device_hip_info(vector<DeviceInfo> &devices)
continue;
}
- int major;
- hipDeviceGetAttribute(&major, hipDeviceAttributeComputeCapabilityMajor, num);
- // TODO : (Arya) What is the last major version we are supporting?
+ if (!hipSupportsDevice(num)) {
+ continue;
+ }
DeviceInfo info;
@@ -141,7 +148,6 @@ void device_hip_info(vector<DeviceInfo> &devices)
info.description = string(name);
info.num = num;
- info.has_half_images = (major >= 3);
info.has_nanovdb = true;
info.denoisers = 0;
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 0e5ac6ce401..4f1cbabc89b 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
@@ -49,12 +47,6 @@ bool HIPDevice::have_precompiled_kernels()
return path_exists(fatbins_path);
}
-bool HIPDevice::show_samples() const
-{
- /* The HIPDevice only processes one tile at a time, so showing samples is fine. */
- return true;
-}
-
BVHLayoutMask HIPDevice::get_bvh_layout_mask() const
{
return BVH_LAYOUT_BVH2;
@@ -101,13 +93,16 @@ HIPDevice::HIPDevice(const DeviceInfo &info, Stats &stats, Profiler &profiler)
}
/* Setup device and context. */
- result = hipGetDevice(&hipDevice, hipDevId);
+ result = hipDeviceGet(&hipDevice, hipDevId);
if (result != hipSuccess) {
set_error(string_printf("Failed to get HIP device handle from ordinal (%s)",
hipewErrorString(result)));
return;
}
+ /* hipDeviceMapHost for mapping host memory when out of device memory.
+ * hipDeviceLmemResizeToMax for reserving local memory ahead of render,
+ * so we can predict which memory to map to host. */
hip_assert(hipDeviceGetAttribute(&can_map_host, hipDeviceAttributeCanMapHostMemory, hipDevice));
hip_assert(
@@ -145,12 +140,18 @@ HIPDevice::~HIPDevice()
bool HIPDevice::support_device(const uint /*kernel_features*/)
{
- int major, minor;
- hipDeviceGetAttribute(&major, hipDeviceAttributeComputeCapabilityMajor, hipDevId);
- hipDeviceGetAttribute(&minor, hipDeviceAttributeComputeCapabilityMinor, hipDevId);
+ if (hipSupportsDevice(hipDevId)) {
+ return true;
+ }
+ else {
+ /* We only support Navi and above. */
+ hipDeviceProp_t props;
+ hipGetDeviceProperties(&props, hipDevId);
- // TODO : (Arya) What versions do we plan to support?
- return true;
+ set_error(string_printf("HIP backend requires AMD RDNA graphics card or up, but found %s.",
+ props.name));
+ return false;
+ }
}
bool HIPDevice::check_peer_access(Device *peer_device)
@@ -205,7 +206,7 @@ bool HIPDevice::use_adaptive_compilation()
return DebugFlags().hip.adaptive_compile;
}
-/* Common NVCC flags which stays the same regardless of shading model,
+/* Common HIPCC flags which stays the same regardless of shading model,
* kernel sources md5 and only depends on compiler or compilation settings.
*/
string HIPDevice::compile_kernel_get_common_cflags(const uint kernel_features)
@@ -215,7 +216,6 @@ string HIPDevice::compile_kernel_get_common_cflags(const uint kernel_features)
const string include_path = source_path;
string cflags = string_printf(
"-m%d "
- "--ptxas-options=\"-v\" "
"--use_fast_math "
"-DHIPCC "
"-I\"%s\"",
@@ -227,45 +227,29 @@ string HIPDevice::compile_kernel_get_common_cflags(const uint kernel_features)
return cflags;
}
-string HIPDevice::compile_kernel(const uint kernel_features,
- const char *name,
- const char *base,
- bool force_ptx)
+string HIPDevice::compile_kernel(const uint kernel_features, const char *name, const char *base)
{
/* Compute kernel name. */
int major, minor;
hipDeviceGetAttribute(&major, hipDeviceAttributeComputeCapabilityMajor, hipDevId);
hipDeviceGetAttribute(&minor, hipDeviceAttributeComputeCapabilityMinor, hipDevId);
+ hipDeviceProp_t props;
+ hipGetDeviceProperties(&props, hipDevId);
+
+ /* gcnArchName can contain tokens after the arch name with features, ie.
+ * `gfx1010:sramecc-:xnack-` so we tokenize it to get the first part. */
+ char *arch = strtok(props.gcnArchName, ":");
+ if (arch == NULL) {
+ arch = props.gcnArchName;
+ }
/* Attempt to use kernel provided with Blender. */
if (!use_adaptive_compilation()) {
- if (!force_ptx) {
- const string fatbin = path_get(string_printf("lib/%s_sm_%d%d.cubin", name, major, minor));
- VLOG(1) << "Testing for pre-compiled kernel " << fatbin << ".";
- if (path_exists(fatbin)) {
- VLOG(1) << "Using precompiled kernel.";
- return fatbin;
- }
- }
-
- /* The driver can JIT-compile PTX generated for older generations, so find the closest one. */
- int ptx_major = major, ptx_minor = minor;
- while (ptx_major >= 3) {
- const string ptx = path_get(
- string_printf("lib/%s_compute_%d%d.ptx", name, ptx_major, ptx_minor));
- VLOG(1) << "Testing for pre-compiled kernel " << ptx << ".";
- if (path_exists(ptx)) {
- VLOG(1) << "Using precompiled kernel.";
- return ptx;
- }
-
- if (ptx_minor > 0) {
- ptx_minor--;
- }
- else {
- ptx_major--;
- ptx_minor = 9;
- }
+ const string fatbin = path_get(string_printf("lib/%s_%s.fatbin", name, arch));
+ VLOG(1) << "Testing for pre-compiled kernel " << fatbin << ".";
+ if (path_exists(fatbin)) {
+ VLOG(1) << "Using precompiled kernel.";
+ return fatbin;
}
}
@@ -280,17 +264,19 @@ string HIPDevice::compile_kernel(const uint kernel_features,
const string kernel_md5 = util_md5_string(source_md5 + common_cflags);
const char *const kernel_ext = "genco";
+ std::string options;
# ifdef _WIN32
- const char *const options =
- "save-temps -Wno-parentheses-equality -Wno-unused-value --hipcc-func-supp";
+ options.append("Wno-parentheses-equality -Wno-unused-value --hipcc-func-supp -ffast-math");
# else
- const char *const options =
- "save-temps -Wno-parentheses-equality -Wno-unused-value --hipcc-func-supp -O3 -ggdb";
+ options.append("Wno-parentheses-equality -Wno-unused-value --hipcc-func-supp -O3 -ffast-math");
+# endif
+# ifdef _DEBUG
+ options.append(" -save-temps");
# endif
+ options.append(" --amdgpu-target=").append(arch);
+
const string include_path = source_path;
- const char *const kernel_arch = force_ptx ? "compute" : "sm";
- const string fatbin_file = string_printf(
- "cycles_%s_%s_%d%d_%s", name, kernel_arch, major, minor, kernel_md5.c_str());
+ const string fatbin_file = string_printf("cycles_%s_%s_%s", name, arch, kernel_md5.c_str());
const string fatbin = path_cache_get(path_join("kernels", fatbin_file));
VLOG(1) << "Testing for locally compiled kernel " << fatbin << ".";
if (path_exists(fatbin)) {
@@ -300,9 +286,9 @@ string HIPDevice::compile_kernel(const uint kernel_features,
# ifdef _WIN32
if (!use_adaptive_compilation() && have_precompiled_kernels()) {
- if (major < 3) {
+ if (!hipSupportsDevice(hipDevId)) {
set_error(
- string_printf("HIP backend requires compute capability 3.0 or up, but found %d.%d. "
+ string_printf("HIP backend requires compute capability 10.1 or up, but found %d.%d. "
"Your GPU is not supported.",
major,
minor));
@@ -347,13 +333,15 @@ string HIPDevice::compile_kernel(const uint kernel_features,
string command = string_printf("%s -%s -I %s --%s %s -o \"%s\"",
hipcc,
- options,
+ options.c_str(),
include_path.c_str(),
kernel_ext,
source_path.c_str(),
fatbin.c_str());
- printf("Compiling HIP kernel ...\n%s\n", command.c_str());
+ printf("Compiling %sHIP kernel ...\n%s\n",
+ (use_adaptive_compilation()) ? "adaptive " : "",
+ command.c_str());
# ifdef _WIN32
command = "call " + command;
@@ -380,13 +368,14 @@ string HIPDevice::compile_kernel(const uint kernel_features,
bool HIPDevice::load_kernels(const uint kernel_features)
{
- /* TODO(sergey): Support kernels re-load for HIP devices.
+ /* TODO(sergey): Support kernels re-load for HIP devices adaptive compile.
*
- * Currently re-loading kernel will invalidate memory pointers,
- * causing problems in hipCtxSynchronize.
+ * Currently re-loading kernels will invalidate memory pointers.
*/
if (hipModule) {
- VLOG(1) << "Skipping kernel reload, not currently supported.";
+ if (use_adaptive_compilation()) {
+ VLOG(1) << "Skipping HIP kernel reload for adaptive compilation, not currently supported.";
+ }
return true;
}
@@ -395,8 +384,9 @@ bool HIPDevice::load_kernels(const uint kernel_features)
return false;
/* check if GPU is supported */
- if (!support_device(kernel_features))
+ if (!support_device(kernel_features)) {
return false;
+ }
/* get kernel */
const char *kernel_name = "kernel";
@@ -427,7 +417,7 @@ bool HIPDevice::load_kernels(const uint kernel_features)
return (result == hipSuccess);
}
-void HIPDevice::reserve_local_memory(const uint)
+void HIPDevice::reserve_local_memory(const uint kernel_features)
{
/* Together with hipDeviceLmemResizeToMax, this reserves local memory
* needed for kernel launches, so that we can reliably figure out when
@@ -441,17 +431,19 @@ void HIPDevice::reserve_local_memory(const uint)
{
/* Use the biggest kernel for estimation. */
- const DeviceKernel test_kernel = DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE;
+ const DeviceKernel test_kernel = (kernel_features & KERNEL_FEATURE_NODE_RAYTRACE) ?
+ DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE :
+ DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE;
/* Launch kernel, using just 1 block appears sufficient to reserve memory for all
* multiprocessors. It would be good to do this in parallel for the multi GPU case
* still to make it faster. */
HIPDeviceQueue queue(this);
- void *d_path_index = nullptr;
- void *d_render_buffer = nullptr;
+ device_ptr d_path_index = 0;
+ device_ptr d_render_buffer = 0;
int d_work_size = 0;
- void *args[] = {&d_path_index, &d_render_buffer, &d_work_size};
+ DeviceKernelArguments args(&d_path_index, &d_render_buffer, &d_work_size);
queue.init_execution();
queue.enqueue(test_kernel, 1, args);
@@ -657,7 +649,8 @@ HIPDevice::HIPMem *HIPDevice::generic_alloc(device_memory &mem, size_t pitch_pad
}
else if (map_host_used + size < map_host_limit) {
/* Allocate host memory ourselves. */
- mem_alloc_result = hipHostMalloc(&shared_pointer, size);
+ mem_alloc_result = hipHostMalloc(
+ &shared_pointer, size, hipHostMallocMapped | hipHostMallocWriteCombined);
assert((mem_alloc_result == hipSuccess && shared_pointer != 0) ||
(mem_alloc_result != hipSuccess && shared_pointer == 0));
@@ -745,6 +738,7 @@ void HIPDevice::generic_free(device_memory &mem)
if (mem.device_pointer) {
HIPContextScope scope(this);
thread_scoped_lock lock(hip_mem_map_mutex);
+ DCHECK(hip_mem_map.find(&mem) != hip_mem_map.end());
const HIPMem &cmem = hip_mem_map[&mem];
/* If cmem.use_mapped_host is true, reference counting is used
@@ -874,7 +868,6 @@ void HIPDevice::const_copy_to(const char *name, void *host, size_t size)
size_t bytes;
hip_assert(hipModuleGetGlobal(&mem, &bytes, hipModule, name));
- assert(bytes == size);
hip_assert(hipMemcpyHtoD(mem, host, size));
}
@@ -899,7 +892,6 @@ void HIPDevice::tex_alloc(device_texture &mem)
{
HIPContextScope scope(this);
- /* General variables for both architectures */
string bind_name = mem.name;
size_t dsize = datatype_size(mem.data_type);
size_t size = mem.memory_size();
@@ -989,16 +981,16 @@ void HIPDevice::tex_alloc(device_texture &mem)
<< string_human_readable_number(mem.memory_size()) << " bytes. ("
<< string_human_readable_size(mem.memory_size()) << ")";
- hip_assert(hipArray3DCreate(&array_3d, &desc));
+ hip_assert(hipArray3DCreate((hArray *)&array_3d, &desc));
if (!array_3d) {
return;
}
HIP_MEMCPY3D param;
- memset(&param, 0, sizeof(param));
+ memset(&param, 0, sizeof(HIP_MEMCPY3D));
param.dstMemoryType = hipMemoryTypeArray;
- param.dstArray = &array_3d;
+ param.dstArray = array_3d;
param.srcMemoryType = hipMemoryTypeHost;
param.srcHost = mem.host_pointer;
param.srcPitch = src_pitch;
@@ -1064,13 +1056,13 @@ void HIPDevice::tex_alloc(device_texture &mem)
if (mem.info.data_type != IMAGE_DATA_TYPE_NANOVDB_FLOAT &&
mem.info.data_type != IMAGE_DATA_TYPE_NANOVDB_FLOAT3) {
- /* Kepler+, bindless textures. */
+ /* Bindless textures. */
hipResourceDesc resDesc;
memset(&resDesc, 0, sizeof(resDesc));
if (array_3d) {
resDesc.resType = hipResourceTypeArray;
- resDesc.res.array.h_Array = &array_3d;
+ resDesc.res.array.h_Array = array_3d;
resDesc.flags = 0;
}
else if (mem.data_height > 0) {
@@ -1115,6 +1107,7 @@ void HIPDevice::tex_free(device_texture &mem)
if (mem.device_pointer) {
HIPContextScope scope(this);
thread_scoped_lock lock(hip_mem_map_mutex);
+ DCHECK(hip_mem_map.find(&mem) != hip_mem_map.end());
const HIPMem &cmem = hip_mem_map[&mem];
if (cmem.texobject) {
@@ -1142,141 +1135,6 @@ void HIPDevice::tex_free(device_texture &mem)
}
}
-# if 0
-void HIPDevice::render(DeviceTask &task,
- RenderTile &rtile,
- device_vector<KernelWorkTile> &work_tiles)
-{
- scoped_timer timer(&rtile.buffers->render_time);
-
- if (have_error())
- return;
-
- HIPContextScope scope(this);
- hipFunction_t hipRender;
-
- /* Get kernel function. */
- if (rtile.task == RenderTile::BAKE) {
- hip_assert(hipModuleGetFunction(&hipRender, hipModule, "kernel_hip_bake"));
- }
- else {
- hip_assert(hipModuleGetFunction(&hipRender, hipModule, "kernel_hip_path_trace"));
- }
-
- if (have_error()) {
- return;
- }
-
- hip_assert(hipFuncSetCacheConfig(hipRender, hipFuncCachePreferL1));
-
- /* Allocate work tile. */
- work_tiles.alloc(1);
-
- KernelWorkTile *wtile = work_tiles.data();
- wtile->x = rtile.x;
- wtile->y = rtile.y;
- wtile->w = rtile.w;
- wtile->h = rtile.h;
- wtile->offset = rtile.offset;
- wtile->stride = rtile.stride;
- wtile->buffer = (float *)(hipDeviceptr_t)rtile.buffer;
-
- /* Prepare work size. More step samples render faster, but for now we
- * remain conservative for GPUs connected to a display to avoid driver
- * timeouts and display freezing. */
- int min_blocks, num_threads_per_block;
- hip_assert(
- hipModuleOccupancyMaxPotentialBlockSize(&min_blocks, &num_threads_per_block, hipRender, NULL, 0, 0));
- if (!info.display_device) {
- min_blocks *= 8;
- }
-
- uint step_samples = divide_up(min_blocks * num_threads_per_block, wtile->w * wtile->h);
-
- /* Render all samples. */
- uint start_sample = rtile.start_sample;
- uint end_sample = rtile.start_sample + rtile.num_samples;
-
- for (int sample = start_sample; sample < end_sample;) {
- /* Setup and copy work tile to device. */
- wtile->start_sample = sample;
- wtile->num_samples = step_samples;
- if (task.adaptive_sampling.use) {
- wtile->num_samples = task.adaptive_sampling.align_samples(sample, step_samples);
- }
- wtile->num_samples = min(wtile->num_samples, end_sample - sample);
- work_tiles.copy_to_device();
-
- hipDeviceptr_t d_work_tiles = (hipDeviceptr_t)work_tiles.device_pointer;
- uint total_work_size = wtile->w * wtile->h * wtile->num_samples;
- uint num_blocks = divide_up(total_work_size, num_threads_per_block);
-
- /* Launch kernel. */
- void *args[] = {&d_work_tiles, &total_work_size};
-
- hip_assert(
- hipModuleLaunchKernel(hipRender, num_blocks, 1, 1, num_threads_per_block, 1, 1, 0, 0, args, 0));
-
- /* Run the adaptive sampling kernels at selected samples aligned to step samples. */
- uint filter_sample = sample + wtile->num_samples - 1;
- if (task.adaptive_sampling.use && task.adaptive_sampling.need_filter(filter_sample)) {
- adaptive_sampling_filter(filter_sample, wtile, d_work_tiles);
- }
-
- hip_assert(hipDeviceSynchronize());
-
- /* Update progress. */
- sample += wtile->num_samples;
- rtile.sample = sample;
- task.update_progress(&rtile, rtile.w * rtile.h * wtile->num_samples);
-
- if (task.get_cancel()) {
- if (task.need_finish_queue == false)
- break;
- }
- }
-
- /* Finalize adaptive sampling. */
- if (task.adaptive_sampling.use) {
- hipDeviceptr_t d_work_tiles = (hipDeviceptr_t)work_tiles.device_pointer;
- adaptive_sampling_post(rtile, wtile, d_work_tiles);
- hip_assert(hipDeviceSynchronize());
- task.update_progress(&rtile, rtile.w * rtile.h * wtile->num_samples);
- }
-}
-
-void HIPDevice::thread_run(DeviceTask &task)
-{
- HIPContextScope scope(this);
-
- if (task.type == DeviceTask::RENDER) {
- device_vector<KernelWorkTile> work_tiles(this, "work_tiles", MEM_READ_ONLY);
-
- /* keep rendering tiles until done */
- RenderTile tile;
- DenoisingTask denoising(this, task);
-
- while (task.acquire_tile(this, tile, task.tile_types)) {
- if (tile.task == RenderTile::PATH_TRACE) {
- render(task, tile, work_tiles);
- }
- else if (tile.task == RenderTile::BAKE) {
- render(task, tile, work_tiles);
- }
-
- task.release_tile(tile);
-
- if (task.get_cancel()) {
- if (task.need_finish_queue == false)
- break;
- }
- }
-
- work_tiles.free();
- }
-}
-# endif
-
unique_ptr<DeviceQueue> HIPDevice::gpu_queue_create()
{
return make_unique<HIPDeviceQueue>(this);
@@ -1290,6 +1148,8 @@ bool HIPDevice::should_use_graphics_interop()
* possible, but from the empiric measurements it can be considerably slower than using naive
* pixels copy. */
+ /* Disable graphics interop for now, because of driver bug in 21.40. See T92972 */
+# if 0
HIPContextScope scope(this);
int num_all_devices = 0;
@@ -1308,6 +1168,7 @@ bool HIPDevice::should_use_graphics_interop()
return true;
}
}
+# endif
return false;
}
diff --git a/intern/cycles/device/hip/device_impl.h b/intern/cycles/device/hip/device_impl.h
index 1d138ee9856..08a7be57e9c 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
@@ -75,8 +75,6 @@ class HIPDevice : public Device {
static bool have_precompiled_kernels();
- virtual bool show_samples() const override;
-
virtual BVHLayoutMask get_bvh_layout_mask() const override;
void set_error(const string &error) override;
@@ -93,10 +91,7 @@ class HIPDevice : public Device {
virtual string compile_kernel_get_common_cflags(const uint kernel_features);
- string compile_kernel(const uint kernel_features,
- const char *name,
- const char *base = "hip",
- bool force_ptx = false);
+ string compile_kernel(const uint kernel_features, const char *name, const char *base = "hip");
virtual bool load_kernels(const uint kernel_features) override;
void reserve_local_memory(const uint kernel_features);
diff --git a/intern/cycles/device/hip/graphics_interop.cpp b/intern/cycles/device/hip/graphics_interop.cpp
index add6dbed5e1..0d5d71019b3 100644
--- a/intern/cycles/device/hip/graphics_interop.cpp
+++ b/intern/cycles/device/hip/graphics_interop.cpp
@@ -37,11 +37,15 @@ HIPDeviceGraphicsInterop::~HIPDeviceGraphicsInterop()
}
}
-void HIPDeviceGraphicsInterop::set_destination(const DeviceGraphicsInteropDestination &destination)
+void HIPDeviceGraphicsInterop::set_display_interop(
+ const DisplayDriver::GraphicsInterop &display_interop)
{
- const int64_t new_buffer_area = int64_t(destination.buffer_width) * destination.buffer_height;
+ const int64_t new_buffer_area = int64_t(display_interop.buffer_width) *
+ display_interop.buffer_height;
- if (opengl_pbo_id_ == destination.opengl_pbo_id && buffer_area_ == new_buffer_area) {
+ need_clear_ = display_interop.need_clear;
+
+ if (opengl_pbo_id_ == display_interop.opengl_pbo_id && buffer_area_ == new_buffer_area) {
return;
}
@@ -52,12 +56,12 @@ void HIPDeviceGraphicsInterop::set_destination(const DeviceGraphicsInteropDestin
}
const hipError_t result = hipGraphicsGLRegisterBuffer(
- &hip_graphics_resource_, destination.opengl_pbo_id, hipGraphicsRegisterFlagsNone);
+ &hip_graphics_resource_, display_interop.opengl_pbo_id, hipGraphicsRegisterFlagsNone);
if (result != hipSuccess) {
LOG(ERROR) << "Error registering OpenGL buffer: " << hipewErrorString(result);
}
- opengl_pbo_id_ = destination.opengl_pbo_id;
+ opengl_pbo_id_ = display_interop.opengl_pbo_id;
buffer_area_ = new_buffer_area;
}
@@ -77,6 +81,14 @@ device_ptr HIPDeviceGraphicsInterop::map()
hip_device_assert(
device_, hipGraphicsResourceGetMappedPointer(&hip_buffer, &bytes, hip_graphics_resource_));
+ if (need_clear_) {
+ hip_device_assert(
+ device_,
+ hipMemsetD8Async(static_cast<hipDeviceptr_t>(hip_buffer), 0, bytes, queue_->stream()));
+
+ need_clear_ = false;
+ }
+
return static_cast<device_ptr>(hip_buffer);
}
diff --git a/intern/cycles/device/hip/graphics_interop.h b/intern/cycles/device/hip/graphics_interop.h
index adcaa13a2d7..71c6893edbd 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"
@@ -39,7 +39,7 @@ class HIPDeviceGraphicsInterop : public DeviceGraphicsInterop {
HIPDeviceGraphicsInterop &operator=(const HIPDeviceGraphicsInterop &other) = delete;
HIPDeviceGraphicsInterop &operator=(HIPDeviceGraphicsInterop &&other) = delete;
- virtual void set_destination(const DeviceGraphicsInteropDestination &destination) override;
+ virtual void set_display_interop(const DisplayDriver::GraphicsInterop &display_interop) override;
virtual device_ptr map() override;
virtual void unmap() override;
@@ -48,11 +48,14 @@ class HIPDeviceGraphicsInterop : public DeviceGraphicsInterop {
HIPDeviceQueue *queue_ = nullptr;
HIPDevice *device_ = nullptr;
- /* OpenGL PBO which is currently registered as the destination for the CUDA buffer. */
+ /* OpenGL PBO which is currently registered as the destination for the HIP buffer. */
uint opengl_pbo_id_ = 0;
/* Buffer area in pixels of the corresponding PBO. */
int64_t buffer_area_ = 0;
+ /* The destination was requested to be cleared. */
+ bool need_clear_ = false;
+
hipGraphicsResource hip_graphics_resource_ = nullptr;
};
diff --git a/intern/cycles/device/hip/kernel.cpp b/intern/cycles/device/hip/kernel.cpp
index e0acd6f17c6..9ede8507a0c 100644
--- a/intern/cycles/device/hip/kernel.cpp
+++ b/intern/cycles/device/hip/kernel.cpp
@@ -28,7 +28,7 @@ void HIPDeviceKernels::load(HIPDevice *device)
for (int i = 0; i < (int)DEVICE_KERNEL_NUM; i++) {
HIPDeviceKernel &kernel = kernels_[i];
- /* No megakernel used for GPU. */
+ /* No mega-kernel used for GPU. */
if (i == DEVICE_KERNEL_INTEGRATOR_MEGAKERNEL) {
continue;
}
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.cpp b/intern/cycles/device/hip/queue.cpp
index 78c77e5fdae..81b283e8cf5 100644
--- a/intern/cycles/device/hip/queue.cpp
+++ b/intern/cycles/device/hip/queue.cpp
@@ -39,11 +39,27 @@ HIPDeviceQueue::~HIPDeviceQueue()
hipStreamDestroy(hip_stream_);
}
-int HIPDeviceQueue::num_concurrent_states(const size_t /*state_size*/) const
+int HIPDeviceQueue::num_concurrent_states(const size_t state_size) const
{
- /* TODO: compute automatically. */
- /* TODO: must have at least num_threads_per_block. */
- return 14416128;
+ const int max_num_threads = hip_device_->get_num_multiprocessors() *
+ hip_device_->get_max_num_threads_per_multiprocessor();
+ int num_states = ((max_num_threads == 0) ? 65536 : max_num_threads) * 16;
+
+ const char *factor_str = getenv("CYCLES_CONCURRENT_STATES_FACTOR");
+ if (factor_str) {
+ const float factor = (float)atof(factor_str);
+ if (factor != 0.0f) {
+ num_states = max((int)(num_states * factor), 1024);
+ }
+ else {
+ VLOG(3) << "CYCLES_CONCURRENT_STATES_FACTOR evaluated to 0";
+ }
+ }
+
+ VLOG(3) << "GPU queue concurrent states: " << num_states << ", using up to "
+ << string_human_readable_size(num_states * state_size);
+
+ return num_states;
}
int HIPDeviceQueue::num_concurrent_busy_states() const
@@ -73,7 +89,9 @@ bool HIPDeviceQueue::kernel_available(DeviceKernel kernel) const
return hip_device_->kernels.available(kernel);
}
-bool HIPDeviceQueue::enqueue(DeviceKernel kernel, const int work_size, void *args[])
+bool HIPDeviceQueue::enqueue(DeviceKernel kernel,
+ const int work_size,
+ DeviceKernelArguments const &args)
{
if (hip_device_->have_error()) {
return false;
@@ -97,6 +115,8 @@ bool HIPDeviceQueue::enqueue(DeviceKernel kernel, const int work_size, void *arg
case DEVICE_KERNEL_INTEGRATOR_TERMINATED_PATHS_ARRAY:
case DEVICE_KERNEL_INTEGRATOR_SORTED_PATHS_ARRAY:
case DEVICE_KERNEL_INTEGRATOR_COMPACT_PATHS_ARRAY:
+ case DEVICE_KERNEL_INTEGRATOR_TERMINATED_SHADOW_PATHS_ARRAY:
+ case DEVICE_KERNEL_INTEGRATOR_COMPACT_SHADOW_PATHS_ARRAY:
/* See parall_active_index.h for why this amount of shared memory is needed. */
shared_mem_bytes = (num_threads_per_block + 1) * sizeof(int);
break;
@@ -105,18 +125,19 @@ bool HIPDeviceQueue::enqueue(DeviceKernel kernel, const int work_size, void *arg
}
/* Launch kernel. */
- hip_device_assert(hip_device_,
- hipModuleLaunchKernel(hip_kernel.function,
- num_blocks,
- 1,
- 1,
- num_threads_per_block,
- 1,
- 1,
- shared_mem_bytes,
- hip_stream_,
- args,
- 0));
+ assert_success(hipModuleLaunchKernel(hip_kernel.function,
+ num_blocks,
+ 1,
+ 1,
+ num_threads_per_block,
+ 1,
+ 1,
+ shared_mem_bytes,
+ hip_stream_,
+ const_cast<void **>(args.values),
+ 0),
+ "enqueue");
+
return !(hip_device_->have_error());
}
@@ -127,7 +148,7 @@ bool HIPDeviceQueue::synchronize()
}
const HIPContextScope scope(hip_device_);
- hip_device_assert(hip_device_, hipStreamSynchronize(hip_stream_));
+ assert_success(hipStreamSynchronize(hip_stream_), "synchronize");
debug_synchronize();
return !(hip_device_->have_error());
@@ -150,9 +171,9 @@ void HIPDeviceQueue::zero_to_device(device_memory &mem)
assert(mem.device_pointer != 0);
const HIPContextScope scope(hip_device_);
- hip_device_assert(
- hip_device_,
- hipMemsetD8Async((hipDeviceptr_t)mem.device_pointer, 0, mem.memory_size(), hip_stream_));
+ assert_success(
+ hipMemsetD8Async((hipDeviceptr_t)mem.device_pointer, 0, mem.memory_size(), hip_stream_),
+ "zero_to_device");
}
void HIPDeviceQueue::copy_to_device(device_memory &mem)
@@ -173,10 +194,10 @@ void HIPDeviceQueue::copy_to_device(device_memory &mem)
/* Copy memory to device. */
const HIPContextScope scope(hip_device_);
- hip_device_assert(
- hip_device_,
+ assert_success(
hipMemcpyHtoDAsync(
- (hipDeviceptr_t)mem.device_pointer, mem.host_pointer, mem.memory_size(), hip_stream_));
+ (hipDeviceptr_t)mem.device_pointer, mem.host_pointer, mem.memory_size(), hip_stream_),
+ "copy_to_device");
}
void HIPDeviceQueue::copy_from_device(device_memory &mem)
@@ -192,13 +213,21 @@ void HIPDeviceQueue::copy_from_device(device_memory &mem)
/* Copy memory from device. */
const HIPContextScope scope(hip_device_);
- hip_device_assert(
- hip_device_,
+ assert_success(
hipMemcpyDtoHAsync(
- mem.host_pointer, (hipDeviceptr_t)mem.device_pointer, mem.memory_size(), hip_stream_));
+ mem.host_pointer, (hipDeviceptr_t)mem.device_pointer, mem.memory_size(), hip_stream_),
+ "copy_from_device");
+}
+
+void HIPDeviceQueue::assert_success(hipError_t result, const char *operation)
+{
+ if (result != hipSuccess) {
+ const char *name = hipewErrorString(result);
+ hip_device_->set_error(
+ string_printf("%s in HIP queue %s (%s)", name, operation, debug_active_kernels().c_str()));
+ }
}
-// TODO : (Arya) Enable this after stabilizing dev branch
unique_ptr<DeviceGraphicsInterop> HIPDeviceQueue::graphics_interop_create()
{
return make_unique<HIPDeviceGraphicsInterop>(this);
diff --git a/intern/cycles/device/hip/queue.h b/intern/cycles/device/hip/queue.h
index 04c8a5982ce..8040d367798 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"
@@ -42,7 +42,9 @@ class HIPDeviceQueue : public DeviceQueue {
virtual bool kernel_available(DeviceKernel kernel) const override;
- virtual bool enqueue(DeviceKernel kernel, const int work_size, void *args[]) override;
+ virtual bool enqueue(DeviceKernel kernel,
+ const int work_size,
+ DeviceKernelArguments const &args) override;
virtual bool synchronize() override;
@@ -55,12 +57,13 @@ class HIPDeviceQueue : public DeviceQueue {
return hip_stream_;
}
- // TODO : (Arya) Enable this after stabilizing the dev branch
virtual unique_ptr<DeviceGraphicsInterop> graphics_interop_create() override;
protected:
HIPDevice *hip_device_;
hipStream_t hip_stream_;
+
+ void assert_success(hipError_t result, const char *operation);
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/device/hip/util.h b/intern/cycles/device/hip/util.h
index 0db5174a3db..e9420becb2d 100644
--- a/intern/cycles/device/hip/util.h
+++ b/intern/cycles/device/hip/util.h
@@ -58,6 +58,15 @@ const char *hipewCompilerPath();
int hipewCompilerVersion();
# endif /* WITH_HIP_DYNLOAD */
+static inline bool hipSupportsDevice(const int hipDevId)
+{
+ int major, minor;
+ hipDeviceGetAttribute(&major, hipDeviceAttributeComputeCapabilityMajor, hipDevId);
+ hipDeviceGetAttribute(&minor, hipDeviceAttributeComputeCapabilityMinor, hipDevId);
+
+ return (major > 10) || (major == 10 && minor >= 1);
+}
+
CCL_NAMESPACE_END
#endif /* WITH_HIP */
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..ba2d993fb9e
--- /dev/null
+++ b/intern/cycles/device/memory.cpp
@@ -0,0 +1,246 @@
+/*
+ * 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),
+ 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()
+{
+ 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..2db3ac9a440
--- /dev/null
+++ b/intern/cycles/device/memory.h
@@ -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.
+ */
+
+#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 = sizeof(T);
+};
+
+template<> struct device_type_traits<uchar> {
+ static const DataType data_type = TYPE_UCHAR;
+ static const size_t num_elements = 1;
+ static_assert(sizeof(uchar) == num_elements * datatype_size(data_type));
+};
+
+template<> struct device_type_traits<uchar2> {
+ static const DataType data_type = TYPE_UCHAR;
+ static const size_t num_elements = 2;
+ static_assert(sizeof(uchar2) == num_elements * datatype_size(data_type));
+};
+
+template<> struct device_type_traits<uchar3> {
+ static const DataType data_type = TYPE_UCHAR;
+ static const size_t num_elements = 3;
+ static_assert(sizeof(uchar3) == num_elements * datatype_size(data_type));
+};
+
+template<> struct device_type_traits<uchar4> {
+ static const DataType data_type = TYPE_UCHAR;
+ static const size_t num_elements = 4;
+ static_assert(sizeof(uchar4) == num_elements * datatype_size(data_type));
+};
+
+template<> struct device_type_traits<uint> {
+ static const DataType data_type = TYPE_UINT;
+ static const size_t num_elements = 1;
+ static_assert(sizeof(uint) == num_elements * datatype_size(data_type));
+};
+
+template<> struct device_type_traits<uint2> {
+ static const DataType data_type = TYPE_UINT;
+ static const size_t num_elements = 2;
+ static_assert(sizeof(uint2) == num_elements * datatype_size(data_type));
+};
+
+template<> struct device_type_traits<uint3> {
+ static const DataType data_type = TYPE_UINT;
+ static const size_t num_elements = 3;
+ static_assert(sizeof(uint3) == num_elements * datatype_size(data_type));
+};
+
+template<> struct device_type_traits<uint4> {
+ static const DataType data_type = TYPE_UINT;
+ static const size_t num_elements = 4;
+ static_assert(sizeof(uint4) == num_elements * datatype_size(data_type));
+};
+
+template<> struct device_type_traits<int> {
+ static const DataType data_type = TYPE_INT;
+ static const size_t num_elements = 1;
+ static_assert(sizeof(int) == num_elements * datatype_size(data_type));
+};
+
+template<> struct device_type_traits<int2> {
+ static const DataType data_type = TYPE_INT;
+ static const size_t num_elements = 2;
+ static_assert(sizeof(int2) == num_elements * datatype_size(data_type));
+};
+
+template<> struct device_type_traits<int3> {
+ static const DataType data_type = TYPE_INT;
+ static const size_t num_elements = 4;
+ static_assert(sizeof(int3) == num_elements * datatype_size(data_type));
+};
+
+template<> struct device_type_traits<int4> {
+ static const DataType data_type = TYPE_INT;
+ static const size_t num_elements = 4;
+ static_assert(sizeof(int4) == num_elements * datatype_size(data_type));
+};
+
+template<> struct device_type_traits<float> {
+ static const DataType data_type = TYPE_FLOAT;
+ static const size_t num_elements = 1;
+ static_assert(sizeof(float) == num_elements * datatype_size(data_type));
+};
+
+template<> struct device_type_traits<float2> {
+ static const DataType data_type = TYPE_FLOAT;
+ static const size_t num_elements = 2;
+ static_assert(sizeof(float2) == num_elements * datatype_size(data_type));
+};
+
+template<> struct device_type_traits<float3> {
+ /* float3 has different size depending on the device, can't use it for interchanging
+ * memory between CPU and GPU.
+ *
+ * Leave body empty to trigger a compile error if used. */
+};
+
+template<> struct device_type_traits<packed_float3> {
+ static const DataType data_type = TYPE_FLOAT;
+ static const size_t num_elements = 3;
+ static_assert(sizeof(packed_float3) == num_elements * datatype_size(data_type));
+};
+
+template<> struct device_type_traits<float4> {
+ static const DataType data_type = TYPE_FLOAT;
+ static const size_t num_elements = 4;
+ static_assert(sizeof(float4) == num_elements * datatype_size(data_type));
+};
+
+template<> struct device_type_traits<half> {
+ static const DataType data_type = TYPE_HALF;
+ static const size_t num_elements = 1;
+ static_assert(sizeof(half) == num_elements * datatype_size(data_type));
+};
+
+template<> struct device_type_traits<ushort4> {
+ static const DataType data_type = TYPE_UINT16;
+ static const size_t num_elements = 4;
+ static_assert(sizeof(ushort4) == num_elements * datatype_size(data_type));
+};
+
+template<> struct device_type_traits<uint16_t> {
+ static const DataType data_type = TYPE_UINT16;
+ static const size_t num_elements = 1;
+ static_assert(sizeof(uint16_t) == num_elements * datatype_size(data_type));
+};
+
+template<> struct device_type_traits<half4> {
+ static const DataType data_type = TYPE_HALF;
+ static const size_t num_elements = 4;
+ static_assert(sizeof(half4) == num_elements * datatype_size(data_type));
+};
+
+template<> struct device_type_traits<uint64_t> {
+ static const DataType data_type = TYPE_UINT64;
+ static const size_t num_elements = 1;
+ static_assert(sizeof(uint64_t) == num_elements * 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;
+ friend class MetalDevice;
+
+ /* Only create through subclasses. */
+ device_memory(Device *device, const char *name, MemoryType type);
+
+ /* No copying and allowed.
+ *
+ * This is because device implementation might need to register device memory in an allocation
+ * map of some sort and use pointer as a key to identify blocks. Moving data from one place to
+ * another bypassing device allocation routines will make those maps hard to maintain. */
+ device_memory(const device_memory &) = delete;
+ device_memory(device_memory &&other) noexcept = delete;
+ device_memory &operator=(const device_memory &) = delete;
+ device_memory &operator=(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_type_traits<T>::num_elements, 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:
+ 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;
+ 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/metal/bvh.h b/intern/cycles/device/metal/bvh.h
new file mode 100644
index 00000000000..58d71e3928f
--- /dev/null
+++ b/intern/cycles/device/metal/bvh.h
@@ -0,0 +1,71 @@
+/*
+ * 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_METAL
+
+# include "bvh/bvh.h"
+# include "bvh/params.h"
+# include "device/memory.h"
+
+# include <Metal/Metal.h>
+
+CCL_NAMESPACE_BEGIN
+
+class BVHMetal : public BVH {
+ public:
+ API_AVAILABLE(macos(11.0))
+ id<MTLAccelerationStructure> accel_struct = nil;
+ bool accel_struct_building = false;
+
+ API_AVAILABLE(macos(11.0))
+ vector<id<MTLAccelerationStructure>> blas_array;
+
+ bool motion_blur = false;
+
+ Stats &stats;
+
+ bool build(Progress &progress, id<MTLDevice> device, id<MTLCommandQueue> queue, bool refit);
+
+ BVHMetal(const BVHParams &params,
+ const vector<Geometry *> &geometry,
+ const vector<Object *> &objects,
+ Device *device);
+ virtual ~BVHMetal();
+
+ bool build_BLAS(Progress &progress, id<MTLDevice> device, id<MTLCommandQueue> queue, bool refit);
+ bool build_BLAS_mesh(Progress &progress,
+ id<MTLDevice> device,
+ id<MTLCommandQueue> queue,
+ Geometry *const geom,
+ bool refit);
+ bool build_BLAS_hair(Progress &progress,
+ id<MTLDevice> device,
+ id<MTLCommandQueue> queue,
+ Geometry *const geom,
+ bool refit);
+ bool build_BLAS_pointcloud(Progress &progress,
+ id<MTLDevice> device,
+ id<MTLCommandQueue> queue,
+ Geometry *const geom,
+ bool refit);
+ bool build_TLAS(Progress &progress, id<MTLDevice> device, id<MTLCommandQueue> queue, bool refit);
+};
+
+CCL_NAMESPACE_END
+
+#endif /* WITH_METAL */
diff --git a/intern/cycles/device/metal/bvh.mm b/intern/cycles/device/metal/bvh.mm
new file mode 100644
index 00000000000..8b252f1a5ec
--- /dev/null
+++ b/intern/cycles/device/metal/bvh.mm
@@ -0,0 +1,1030 @@
+/*
+ * 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.
+ */
+
+#ifdef WITH_METAL
+
+# include "scene/hair.h"
+# include "scene/mesh.h"
+# include "scene/object.h"
+# include "scene/pointcloud.h"
+
+# include "util/progress.h"
+
+# include "device/metal/bvh.h"
+
+CCL_NAMESPACE_BEGIN
+
+# define BVH_status(...) \
+ { \
+ string str = string_printf(__VA_ARGS__); \
+ progress.set_substatus(str); \
+ }
+
+BVHMetal::BVHMetal(const BVHParams &params_,
+ const vector<Geometry *> &geometry_,
+ const vector<Object *> &objects_,
+ Device *device)
+ : BVH(params_, geometry_, objects_), stats(device->stats)
+{
+}
+
+BVHMetal::~BVHMetal()
+{
+ if (@available(macos 12.0, *)) {
+ if (accel_struct) {
+ stats.mem_free(accel_struct.allocatedSize);
+ [accel_struct release];
+ }
+ }
+}
+
+bool BVHMetal::build_BLAS_mesh(Progress &progress,
+ id<MTLDevice> device,
+ id<MTLCommandQueue> queue,
+ Geometry *const geom,
+ bool refit)
+{
+ if (@available(macos 12.0, *)) {
+ /* Build BLAS for triangle primitives */
+ Mesh *const mesh = static_cast<Mesh *const>(geom);
+ if (mesh->num_triangles() == 0) {
+ return false;
+ }
+
+ /*------------------------------------------------*/
+ BVH_status(
+ "Building mesh BLAS | %7d tris | %s", (int)mesh->num_triangles(), geom->name.c_str());
+ /*------------------------------------------------*/
+
+ const bool use_fast_trace_bvh = (params.bvh_type == BVH_TYPE_STATIC);
+
+ const array<float3> &verts = mesh->get_verts();
+ const array<int> &tris = mesh->get_triangles();
+ const size_t num_verts = verts.size();
+ const size_t num_indices = tris.size();
+
+ size_t num_motion_steps = 1;
+ Attribute *motion_keys = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ if (motion_blur && mesh->get_use_motion_blur() && motion_keys) {
+ num_motion_steps = mesh->get_motion_steps();
+ }
+
+ MTLResourceOptions storage_mode;
+ if (device.hasUnifiedMemory) {
+ storage_mode = MTLResourceStorageModeShared;
+ }
+ else {
+ storage_mode = MTLResourceStorageModeManaged;
+ }
+
+ /* Upload the mesh data to the GPU */
+ id<MTLBuffer> posBuf = nil;
+ id<MTLBuffer> indexBuf = [device newBufferWithBytes:tris.data()
+ length:num_indices * sizeof(tris.data()[0])
+ options:storage_mode];
+
+ if (num_motion_steps == 1) {
+ posBuf = [device newBufferWithBytes:verts.data()
+ length:num_verts * sizeof(verts.data()[0])
+ options:storage_mode];
+ }
+ else {
+ posBuf = [device newBufferWithLength:num_verts * num_motion_steps * sizeof(verts.data()[0])
+ options:storage_mode];
+ float3 *dest_data = (float3 *)[posBuf contents];
+ size_t center_step = (num_motion_steps - 1) / 2;
+ for (size_t step = 0; step < num_motion_steps; ++step) {
+ const float3 *verts = mesh->get_verts().data();
+
+ /* The center step for motion vertices is not stored in the attribute. */
+ if (step != center_step) {
+ verts = motion_keys->data_float3() + (step > center_step ? step - 1 : step) * num_verts;
+ }
+ memcpy(dest_data + num_verts * step, verts, num_verts * sizeof(float3));
+ }
+ if (storage_mode == MTLResourceStorageModeManaged) {
+ [posBuf didModifyRange:NSMakeRange(0, posBuf.length)];
+ }
+ }
+
+ /* Create an acceleration structure. */
+ MTLAccelerationStructureGeometryDescriptor *geomDesc;
+ if (num_motion_steps > 1) {
+ std::vector<MTLMotionKeyframeData *> vertex_ptrs;
+ vertex_ptrs.reserve(num_motion_steps);
+ for (size_t step = 0; step < num_motion_steps; ++step) {
+ MTLMotionKeyframeData *k = [MTLMotionKeyframeData data];
+ k.buffer = posBuf;
+ k.offset = num_verts * step * sizeof(float3);
+ vertex_ptrs.push_back(k);
+ }
+
+ MTLAccelerationStructureMotionTriangleGeometryDescriptor *geomDescMotion =
+ [MTLAccelerationStructureMotionTriangleGeometryDescriptor descriptor];
+ geomDescMotion.vertexBuffers = [NSArray arrayWithObjects:vertex_ptrs.data()
+ count:vertex_ptrs.size()];
+ geomDescMotion.vertexStride = sizeof(verts.data()[0]);
+ geomDescMotion.indexBuffer = indexBuf;
+ geomDescMotion.indexBufferOffset = 0;
+ geomDescMotion.indexType = MTLIndexTypeUInt32;
+ geomDescMotion.triangleCount = num_indices / 3;
+ geomDescMotion.intersectionFunctionTableOffset = 0;
+
+ geomDesc = geomDescMotion;
+ }
+ else {
+ MTLAccelerationStructureTriangleGeometryDescriptor *geomDescNoMotion =
+ [MTLAccelerationStructureTriangleGeometryDescriptor descriptor];
+ geomDescNoMotion.vertexBuffer = posBuf;
+ geomDescNoMotion.vertexBufferOffset = 0;
+ geomDescNoMotion.vertexStride = sizeof(verts.data()[0]);
+ geomDescNoMotion.indexBuffer = indexBuf;
+ geomDescNoMotion.indexBufferOffset = 0;
+ geomDescNoMotion.indexType = MTLIndexTypeUInt32;
+ geomDescNoMotion.triangleCount = num_indices / 3;
+ geomDescNoMotion.intersectionFunctionTableOffset = 0;
+
+ geomDesc = geomDescNoMotion;
+ }
+
+ /* Force a single any-hit call, so shadow record-all behavior works correctly */
+ /* (Match optix behavior: unsigned int build_flags =
+ * OPTIX_GEOMETRY_FLAG_REQUIRE_SINGLE_ANYHIT_CALL;) */
+ geomDesc.allowDuplicateIntersectionFunctionInvocation = false;
+
+ MTLPrimitiveAccelerationStructureDescriptor *accelDesc =
+ [MTLPrimitiveAccelerationStructureDescriptor descriptor];
+ accelDesc.geometryDescriptors = @[ geomDesc ];
+ if (num_motion_steps > 1) {
+ accelDesc.motionStartTime = 0.0f;
+ accelDesc.motionEndTime = 1.0f;
+ accelDesc.motionStartBorderMode = MTLMotionBorderModeClamp;
+ accelDesc.motionEndBorderMode = MTLMotionBorderModeClamp;
+ accelDesc.motionKeyframeCount = num_motion_steps;
+ }
+
+ if (!use_fast_trace_bvh) {
+ accelDesc.usage |= (MTLAccelerationStructureUsageRefit |
+ MTLAccelerationStructureUsagePreferFastBuild);
+ }
+
+ MTLAccelerationStructureSizes accelSizes = [device
+ accelerationStructureSizesWithDescriptor:accelDesc];
+ id<MTLAccelerationStructure> accel_uncompressed = [device
+ newAccelerationStructureWithSize:accelSizes.accelerationStructureSize];
+ id<MTLBuffer> scratchBuf = [device newBufferWithLength:accelSizes.buildScratchBufferSize
+ options:MTLResourceStorageModePrivate];
+ id<MTLBuffer> sizeBuf = [device newBufferWithLength:8 options:MTLResourceStorageModeShared];
+ id<MTLCommandBuffer> accelCommands = [queue commandBuffer];
+ id<MTLAccelerationStructureCommandEncoder> accelEnc =
+ [accelCommands accelerationStructureCommandEncoder];
+ if (refit) {
+ [accelEnc refitAccelerationStructure:accel_struct
+ descriptor:accelDesc
+ destination:accel_uncompressed
+ scratchBuffer:scratchBuf
+ scratchBufferOffset:0];
+ }
+ else {
+ [accelEnc buildAccelerationStructure:accel_uncompressed
+ descriptor:accelDesc
+ scratchBuffer:scratchBuf
+ scratchBufferOffset:0];
+ }
+ if (use_fast_trace_bvh) {
+ [accelEnc writeCompactedAccelerationStructureSize:accel_uncompressed
+ toBuffer:sizeBuf
+ offset:0
+ sizeDataType:MTLDataTypeULong];
+ }
+ [accelEnc endEncoding];
+ [accelCommands addCompletedHandler:^(id<MTLCommandBuffer> command_buffer) {
+ /* free temp resources */
+ [scratchBuf release];
+ [indexBuf release];
+ [posBuf release];
+
+ if (use_fast_trace_bvh) {
+ /* Compact the accel structure */
+ uint64_t compressed_size = *(uint64_t *)sizeBuf.contents;
+
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+ id<MTLCommandBuffer> accelCommands = [queue commandBuffer];
+ id<MTLAccelerationStructureCommandEncoder> accelEnc =
+ [accelCommands accelerationStructureCommandEncoder];
+ id<MTLAccelerationStructure> accel = [device
+ newAccelerationStructureWithSize:compressed_size];
+ [accelEnc copyAndCompactAccelerationStructure:accel_uncompressed
+ toAccelerationStructure:accel];
+ [accelEnc endEncoding];
+ [accelCommands addCompletedHandler:^(id<MTLCommandBuffer> command_buffer) {
+ uint64_t allocated_size = [accel allocatedSize];
+ stats.mem_alloc(allocated_size);
+ accel_struct = accel;
+ [accel_uncompressed release];
+ accel_struct_building = false;
+ }];
+ [accelCommands commit];
+ });
+ }
+ else {
+ /* set our acceleration structure to the uncompressed structure */
+ accel_struct = accel_uncompressed;
+
+ uint64_t allocated_size = [accel_struct allocatedSize];
+ stats.mem_alloc(allocated_size);
+ accel_struct_building = false;
+ }
+ [sizeBuf release];
+ }];
+
+ accel_struct_building = true;
+ [accelCommands commit];
+
+ return true;
+ }
+ return false;
+}
+
+bool BVHMetal::build_BLAS_hair(Progress &progress,
+ id<MTLDevice> device,
+ id<MTLCommandQueue> queue,
+ Geometry *const geom,
+ bool refit)
+{
+ if (@available(macos 12.0, *)) {
+ /* Build BLAS for hair curves */
+ Hair *hair = static_cast<Hair *>(geom);
+ if (hair->num_curves() == 0) {
+ return false;
+ }
+
+ /*------------------------------------------------*/
+ BVH_status(
+ "Building hair BLAS | %7d curves | %s", (int)hair->num_curves(), geom->name.c_str());
+ /*------------------------------------------------*/
+
+ const bool use_fast_trace_bvh = (params.bvh_type == BVH_TYPE_STATIC);
+ const size_t num_segments = hair->num_segments();
+
+ size_t num_motion_steps = 1;
+ Attribute *motion_keys = hair->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ if (motion_blur && hair->get_use_motion_blur() && motion_keys) {
+ num_motion_steps = hair->get_motion_steps();
+ }
+
+ const size_t num_aabbs = num_segments * num_motion_steps;
+
+ MTLResourceOptions storage_mode;
+ if (device.hasUnifiedMemory) {
+ storage_mode = MTLResourceStorageModeShared;
+ }
+ else {
+ storage_mode = MTLResourceStorageModeManaged;
+ }
+
+ /* Allocate a GPU buffer for the AABB data and populate it */
+ id<MTLBuffer> aabbBuf = [device
+ newBufferWithLength:num_aabbs * sizeof(MTLAxisAlignedBoundingBox)
+ options:storage_mode];
+ MTLAxisAlignedBoundingBox *aabb_data = (MTLAxisAlignedBoundingBox *)[aabbBuf contents];
+
+ /* Get AABBs for each motion step */
+ size_t center_step = (num_motion_steps - 1) / 2;
+ for (size_t step = 0; step < num_motion_steps; ++step) {
+ /* The center step for motion vertices is not stored in the attribute */
+ const float3 *keys = hair->get_curve_keys().data();
+ if (step != center_step) {
+ size_t attr_offset = (step > center_step) ? step - 1 : step;
+ /* Technically this is a float4 array, but sizeof(float3) == sizeof(float4) */
+ keys = motion_keys->data_float3() + attr_offset * hair->get_curve_keys().size();
+ }
+
+ for (size_t j = 0, i = 0; j < hair->num_curves(); ++j) {
+ const Hair::Curve curve = hair->get_curve(j);
+
+ for (int segment = 0; segment < curve.num_segments(); ++segment, ++i) {
+ {
+ BoundBox bounds = BoundBox::empty;
+ curve.bounds_grow(segment, keys, hair->get_curve_radius().data(), bounds);
+
+ const size_t index = step * num_segments + i;
+ aabb_data[index].min = (MTLPackedFloat3 &)bounds.min;
+ aabb_data[index].max = (MTLPackedFloat3 &)bounds.max;
+ }
+ }
+ }
+ }
+
+ if (storage_mode == MTLResourceStorageModeManaged) {
+ [aabbBuf didModifyRange:NSMakeRange(0, aabbBuf.length)];
+ }
+
+# if 0
+ for (size_t i=0; i<num_aabbs && i < 400; i++) {
+ MTLAxisAlignedBoundingBox& bb = aabb_data[i];
+ printf(" %d: %.1f,%.1f,%.1f -- %.1f,%.1f,%.1f\n", int(i), bb.min.x, bb.min.y, bb.min.z, bb.max.x, bb.max.y, bb.max.z);
+ }
+# endif
+
+ MTLAccelerationStructureGeometryDescriptor *geomDesc;
+ if (motion_blur) {
+ std::vector<MTLMotionKeyframeData *> aabb_ptrs;
+ aabb_ptrs.reserve(num_motion_steps);
+ for (size_t step = 0; step < num_motion_steps; ++step) {
+ MTLMotionKeyframeData *k = [MTLMotionKeyframeData data];
+ k.buffer = aabbBuf;
+ k.offset = step * num_segments * sizeof(MTLAxisAlignedBoundingBox);
+ aabb_ptrs.push_back(k);
+ }
+
+ MTLAccelerationStructureMotionBoundingBoxGeometryDescriptor *geomDescMotion =
+ [MTLAccelerationStructureMotionBoundingBoxGeometryDescriptor descriptor];
+ geomDescMotion.boundingBoxBuffers = [NSArray arrayWithObjects:aabb_ptrs.data()
+ count:aabb_ptrs.size()];
+ geomDescMotion.boundingBoxCount = num_segments;
+ geomDescMotion.boundingBoxStride = sizeof(aabb_data[0]);
+ geomDescMotion.intersectionFunctionTableOffset = 1;
+
+ /* Force a single any-hit call, so shadow record-all behavior works correctly */
+ /* (Match optix behavior: unsigned int build_flags =
+ * OPTIX_GEOMETRY_FLAG_REQUIRE_SINGLE_ANYHIT_CALL;) */
+ geomDescMotion.allowDuplicateIntersectionFunctionInvocation = false;
+ geomDescMotion.opaque = true;
+ geomDesc = geomDescMotion;
+ }
+ else {
+ MTLAccelerationStructureBoundingBoxGeometryDescriptor *geomDescNoMotion =
+ [MTLAccelerationStructureBoundingBoxGeometryDescriptor descriptor];
+ geomDescNoMotion.boundingBoxBuffer = aabbBuf;
+ geomDescNoMotion.boundingBoxBufferOffset = 0;
+ geomDescNoMotion.boundingBoxCount = int(num_aabbs);
+ geomDescNoMotion.boundingBoxStride = sizeof(aabb_data[0]);
+ geomDescNoMotion.intersectionFunctionTableOffset = 1;
+
+ /* Force a single any-hit call, so shadow record-all behavior works correctly */
+ /* (Match optix behavior: unsigned int build_flags =
+ * OPTIX_GEOMETRY_FLAG_REQUIRE_SINGLE_ANYHIT_CALL;) */
+ geomDescNoMotion.allowDuplicateIntersectionFunctionInvocation = false;
+ geomDescNoMotion.opaque = true;
+ geomDesc = geomDescNoMotion;
+ }
+
+ MTLPrimitiveAccelerationStructureDescriptor *accelDesc =
+ [MTLPrimitiveAccelerationStructureDescriptor descriptor];
+ accelDesc.geometryDescriptors = @[ geomDesc ];
+
+ if (motion_blur) {
+ accelDesc.motionStartTime = 0.0f;
+ accelDesc.motionEndTime = 1.0f;
+ accelDesc.motionStartBorderMode = MTLMotionBorderModeVanish;
+ accelDesc.motionEndBorderMode = MTLMotionBorderModeVanish;
+ accelDesc.motionKeyframeCount = num_motion_steps;
+ }
+
+ if (!use_fast_trace_bvh) {
+ accelDesc.usage |= (MTLAccelerationStructureUsageRefit |
+ MTLAccelerationStructureUsagePreferFastBuild);
+ }
+
+ MTLAccelerationStructureSizes accelSizes = [device
+ accelerationStructureSizesWithDescriptor:accelDesc];
+ id<MTLAccelerationStructure> accel_uncompressed = [device
+ newAccelerationStructureWithSize:accelSizes.accelerationStructureSize];
+ id<MTLBuffer> scratchBuf = [device newBufferWithLength:accelSizes.buildScratchBufferSize
+ options:MTLResourceStorageModePrivate];
+ id<MTLBuffer> sizeBuf = [device newBufferWithLength:8 options:MTLResourceStorageModeShared];
+ id<MTLCommandBuffer> accelCommands = [queue commandBuffer];
+ id<MTLAccelerationStructureCommandEncoder> accelEnc =
+ [accelCommands accelerationStructureCommandEncoder];
+ if (refit) {
+ [accelEnc refitAccelerationStructure:accel_struct
+ descriptor:accelDesc
+ destination:accel_uncompressed
+ scratchBuffer:scratchBuf
+ scratchBufferOffset:0];
+ }
+ else {
+ [accelEnc buildAccelerationStructure:accel_uncompressed
+ descriptor:accelDesc
+ scratchBuffer:scratchBuf
+ scratchBufferOffset:0];
+ }
+ if (use_fast_trace_bvh) {
+ [accelEnc writeCompactedAccelerationStructureSize:accel_uncompressed
+ toBuffer:sizeBuf
+ offset:0
+ sizeDataType:MTLDataTypeULong];
+ }
+ [accelEnc endEncoding];
+ [accelCommands addCompletedHandler:^(id<MTLCommandBuffer> command_buffer) {
+ /* free temp resources */
+ [scratchBuf release];
+ [aabbBuf release];
+
+ if (use_fast_trace_bvh) {
+ /* Compact the accel structure */
+ uint64_t compressed_size = *(uint64_t *)sizeBuf.contents;
+
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+ id<MTLCommandBuffer> accelCommands = [queue commandBuffer];
+ id<MTLAccelerationStructureCommandEncoder> accelEnc =
+ [accelCommands accelerationStructureCommandEncoder];
+ id<MTLAccelerationStructure> accel = [device
+ newAccelerationStructureWithSize:compressed_size];
+ [accelEnc copyAndCompactAccelerationStructure:accel_uncompressed
+ toAccelerationStructure:accel];
+ [accelEnc endEncoding];
+ [accelCommands addCompletedHandler:^(id<MTLCommandBuffer> command_buffer) {
+ uint64_t allocated_size = [accel allocatedSize];
+ stats.mem_alloc(allocated_size);
+ accel_struct = accel;
+ [accel_uncompressed release];
+ accel_struct_building = false;
+ }];
+ [accelCommands commit];
+ });
+ }
+ else {
+ /* set our acceleration structure to the uncompressed structure */
+ accel_struct = accel_uncompressed;
+
+ uint64_t allocated_size = [accel_struct allocatedSize];
+ stats.mem_alloc(allocated_size);
+ accel_struct_building = false;
+ }
+ [sizeBuf release];
+ }];
+
+ accel_struct_building = true;
+ [accelCommands commit];
+ return true;
+ }
+ return false;
+}
+
+bool BVHMetal::build_BLAS_pointcloud(Progress &progress,
+ id<MTLDevice> device,
+ id<MTLCommandQueue> queue,
+ Geometry *const geom,
+ bool refit)
+{
+ if (@available(macos 12.0, *)) {
+ /* Build BLAS for point cloud */
+ PointCloud *pointcloud = static_cast<PointCloud *>(geom);
+ if (pointcloud->num_points() == 0) {
+ return false;
+ }
+
+ /*------------------------------------------------*/
+ BVH_status("Building pointcloud BLAS | %7d points | %s",
+ (int)pointcloud->num_points(),
+ geom->name.c_str());
+ /*------------------------------------------------*/
+
+ const size_t num_points = pointcloud->get_points().size();
+ const float3 *points = pointcloud->get_points().data();
+ const float *radius = pointcloud->get_radius().data();
+
+ const bool use_fast_trace_bvh = (params.bvh_type == BVH_TYPE_STATIC);
+
+ size_t num_motion_steps = 1;
+ Attribute *motion_keys = pointcloud->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ if (motion_blur && pointcloud->get_use_motion_blur() && motion_keys) {
+ num_motion_steps = pointcloud->get_motion_steps();
+ }
+
+ const size_t num_aabbs = num_motion_steps;
+
+ MTLResourceOptions storage_mode;
+ if (device.hasUnifiedMemory) {
+ storage_mode = MTLResourceStorageModeShared;
+ }
+ else {
+ storage_mode = MTLResourceStorageModeManaged;
+ }
+
+ /* Allocate a GPU buffer for the AABB data and populate it */
+ id<MTLBuffer> aabbBuf = [device
+ newBufferWithLength:num_aabbs * sizeof(MTLAxisAlignedBoundingBox)
+ options:storage_mode];
+ MTLAxisAlignedBoundingBox *aabb_data = (MTLAxisAlignedBoundingBox *)[aabbBuf contents];
+
+ /* Get AABBs for each motion step */
+ size_t center_step = (num_motion_steps - 1) / 2;
+ for (size_t step = 0; step < num_motion_steps; ++step) {
+ /* The center step for motion vertices is not stored in the attribute */
+ if (step != center_step) {
+ size_t attr_offset = (step > center_step) ? step - 1 : step;
+ points = motion_keys->data_float3() + attr_offset * num_points;
+ }
+
+ for (size_t j = 0; j < num_points; ++j) {
+ const PointCloud::Point point = pointcloud->get_point(j);
+ BoundBox bounds = BoundBox::empty;
+ point.bounds_grow(points, radius, bounds);
+
+ const size_t index = step * num_points + j;
+ aabb_data[index].min = (MTLPackedFloat3 &)bounds.min;
+ aabb_data[index].max = (MTLPackedFloat3 &)bounds.max;
+ }
+ }
+
+ if (storage_mode == MTLResourceStorageModeManaged) {
+ [aabbBuf didModifyRange:NSMakeRange(0, aabbBuf.length)];
+ }
+
+# if 0
+ for (size_t i=0; i<num_aabbs && i < 400; i++) {
+ MTLAxisAlignedBoundingBox& bb = aabb_data[i];
+ printf(" %d: %.1f,%.1f,%.1f -- %.1f,%.1f,%.1f\n", int(i), bb.min.x, bb.min.y, bb.min.z, bb.max.x, bb.max.y, bb.max.z);
+ }
+# endif
+
+ MTLAccelerationStructureGeometryDescriptor *geomDesc;
+ if (motion_blur) {
+ std::vector<MTLMotionKeyframeData *> aabb_ptrs;
+ aabb_ptrs.reserve(num_motion_steps);
+ for (size_t step = 0; step < num_motion_steps; ++step) {
+ MTLMotionKeyframeData *k = [MTLMotionKeyframeData data];
+ k.buffer = aabbBuf;
+ k.offset = step * num_points * sizeof(MTLAxisAlignedBoundingBox);
+ aabb_ptrs.push_back(k);
+ }
+
+ MTLAccelerationStructureMotionBoundingBoxGeometryDescriptor *geomDescMotion =
+ [MTLAccelerationStructureMotionBoundingBoxGeometryDescriptor descriptor];
+ geomDescMotion.boundingBoxBuffers = [NSArray arrayWithObjects:aabb_ptrs.data()
+ count:aabb_ptrs.size()];
+ geomDescMotion.boundingBoxCount = num_points;
+ geomDescMotion.boundingBoxStride = sizeof(aabb_data[0]);
+ geomDescMotion.intersectionFunctionTableOffset = 2;
+
+ /* Force a single any-hit call, so shadow record-all behavior works correctly */
+ /* (Match optix behavior: unsigned int build_flags =
+ * OPTIX_GEOMETRY_FLAG_REQUIRE_SINGLE_ANYHIT_CALL;) */
+ geomDescMotion.allowDuplicateIntersectionFunctionInvocation = false;
+ geomDescMotion.opaque = true;
+ geomDesc = geomDescMotion;
+ }
+ else {
+ MTLAccelerationStructureBoundingBoxGeometryDescriptor *geomDescNoMotion =
+ [MTLAccelerationStructureBoundingBoxGeometryDescriptor descriptor];
+ geomDescNoMotion.boundingBoxBuffer = aabbBuf;
+ geomDescNoMotion.boundingBoxBufferOffset = 0;
+ geomDescNoMotion.boundingBoxCount = int(num_aabbs);
+ geomDescNoMotion.boundingBoxStride = sizeof(aabb_data[0]);
+ geomDescNoMotion.intersectionFunctionTableOffset = 2;
+
+ /* Force a single any-hit call, so shadow record-all behavior works correctly */
+ /* (Match optix behavior: unsigned int build_flags =
+ * OPTIX_GEOMETRY_FLAG_REQUIRE_SINGLE_ANYHIT_CALL;) */
+ geomDescNoMotion.allowDuplicateIntersectionFunctionInvocation = false;
+ geomDescNoMotion.opaque = true;
+ geomDesc = geomDescNoMotion;
+ }
+
+ MTLPrimitiveAccelerationStructureDescriptor *accelDesc =
+ [MTLPrimitiveAccelerationStructureDescriptor descriptor];
+ accelDesc.geometryDescriptors = @[ geomDesc ];
+
+ if (motion_blur) {
+ accelDesc.motionStartTime = 0.0f;
+ accelDesc.motionEndTime = 1.0f;
+ accelDesc.motionStartBorderMode = MTLMotionBorderModeVanish;
+ accelDesc.motionEndBorderMode = MTLMotionBorderModeVanish;
+ accelDesc.motionKeyframeCount = num_motion_steps;
+ }
+
+ if (!use_fast_trace_bvh) {
+ accelDesc.usage |= (MTLAccelerationStructureUsageRefit |
+ MTLAccelerationStructureUsagePreferFastBuild);
+ }
+
+ MTLAccelerationStructureSizes accelSizes = [device
+ accelerationStructureSizesWithDescriptor:accelDesc];
+ id<MTLAccelerationStructure> accel_uncompressed = [device
+ newAccelerationStructureWithSize:accelSizes.accelerationStructureSize];
+ id<MTLBuffer> scratchBuf = [device newBufferWithLength:accelSizes.buildScratchBufferSize
+ options:MTLResourceStorageModePrivate];
+ id<MTLBuffer> sizeBuf = [device newBufferWithLength:8 options:MTLResourceStorageModeShared];
+ id<MTLCommandBuffer> accelCommands = [queue commandBuffer];
+ id<MTLAccelerationStructureCommandEncoder> accelEnc =
+ [accelCommands accelerationStructureCommandEncoder];
+ if (refit) {
+ [accelEnc refitAccelerationStructure:accel_struct
+ descriptor:accelDesc
+ destination:accel_uncompressed
+ scratchBuffer:scratchBuf
+ scratchBufferOffset:0];
+ }
+ else {
+ [accelEnc buildAccelerationStructure:accel_uncompressed
+ descriptor:accelDesc
+ scratchBuffer:scratchBuf
+ scratchBufferOffset:0];
+ }
+ if (use_fast_trace_bvh) {
+ [accelEnc writeCompactedAccelerationStructureSize:accel_uncompressed
+ toBuffer:sizeBuf
+ offset:0
+ sizeDataType:MTLDataTypeULong];
+ }
+ [accelEnc endEncoding];
+ [accelCommands addCompletedHandler:^(id<MTLCommandBuffer> command_buffer) {
+ /* free temp resources */
+ [scratchBuf release];
+ [aabbBuf release];
+
+ if (use_fast_trace_bvh) {
+ /* Compact the accel structure */
+ uint64_t compressed_size = *(uint64_t *)sizeBuf.contents;
+
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+ id<MTLCommandBuffer> accelCommands = [queue commandBuffer];
+ id<MTLAccelerationStructureCommandEncoder> accelEnc =
+ [accelCommands accelerationStructureCommandEncoder];
+ id<MTLAccelerationStructure> accel = [device
+ newAccelerationStructureWithSize:compressed_size];
+ [accelEnc copyAndCompactAccelerationStructure:accel_uncompressed
+ toAccelerationStructure:accel];
+ [accelEnc endEncoding];
+ [accelCommands addCompletedHandler:^(id<MTLCommandBuffer> command_buffer) {
+ uint64_t allocated_size = [accel allocatedSize];
+ stats.mem_alloc(allocated_size);
+ accel_struct = accel;
+ [accel_uncompressed release];
+ accel_struct_building = false;
+ }];
+ [accelCommands commit];
+ });
+ }
+ else {
+ /* set our acceleration structure to the uncompressed structure */
+ accel_struct = accel_uncompressed;
+
+ uint64_t allocated_size = [accel_struct allocatedSize];
+ stats.mem_alloc(allocated_size);
+ accel_struct_building = false;
+ }
+ [sizeBuf release];
+ }];
+
+ accel_struct_building = true;
+ [accelCommands commit];
+ return true;
+ }
+ return false;
+}
+
+bool BVHMetal::build_BLAS(Progress &progress,
+ id<MTLDevice> device,
+ id<MTLCommandQueue> queue,
+ bool refit)
+{
+ if (@available(macos 12.0, *)) {
+ assert(objects.size() == 1 && geometry.size() == 1);
+
+ /* Build bottom level acceleration structures (BLAS) */
+ Geometry *const geom = geometry[0];
+ switch (geom->geometry_type) {
+ case Geometry::VOLUME:
+ case Geometry::MESH:
+ return build_BLAS_mesh(progress, device, queue, geom, refit);
+ case Geometry::HAIR:
+ return build_BLAS_hair(progress, device, queue, geom, refit);
+ case Geometry::POINTCLOUD:
+ return build_BLAS_pointcloud(progress, device, queue, geom, refit);
+ default:
+ return false;
+ }
+ }
+ return false;
+}
+
+bool BVHMetal::build_TLAS(Progress &progress,
+ id<MTLDevice> device,
+ id<MTLCommandQueue> queue,
+ bool refit)
+{
+ if (@available(macos 12.0, *)) {
+
+ /* we need to sync here and ensure that all BLAS have completed async generation by both GCD
+ * and Metal */
+ {
+ __block bool complete_bvh = false;
+ while (!complete_bvh) {
+ dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+ complete_bvh = true;
+ for (Object *ob : objects) {
+ /* Skip non-traceable objects */
+ if (!ob->is_traceable())
+ continue;
+
+ Geometry const *geom = ob->get_geometry();
+ BVHMetal const *blas = static_cast<BVHMetal const *>(geom->bvh);
+ if (blas->accel_struct_building) {
+ complete_bvh = false;
+
+ /* We're likely waiting on a command buffer that's in flight to complete.
+ * Queue up a command buffer and wait for it complete before checking the BLAS again
+ */
+ id<MTLCommandBuffer> command_buffer = [queue commandBuffer];
+ [command_buffer commit];
+ [command_buffer waitUntilCompleted];
+ break;
+ }
+ }
+ });
+ }
+ }
+
+ uint32_t num_instances = 0;
+ uint32_t num_motion_transforms = 0;
+ for (Object *ob : objects) {
+ /* Skip non-traceable objects */
+ if (!ob->is_traceable())
+ continue;
+ num_instances++;
+
+ if (ob->use_motion()) {
+ num_motion_transforms += max(1, ob->get_motion().size());
+ }
+ else {
+ num_motion_transforms++;
+ }
+ }
+
+ /*------------------------------------------------*/
+ BVH_status("Building TLAS | %7d instances", (int)num_instances);
+ /*------------------------------------------------*/
+
+ const bool use_fast_trace_bvh = (params.bvh_type == BVH_TYPE_STATIC);
+
+ NSMutableArray *all_blas = [NSMutableArray array];
+ unordered_map<BVHMetal const *, int> instance_mapping;
+
+ /* Lambda function to build/retrieve the BLAS index mapping */
+ auto get_blas_index = [&](BVHMetal const *blas) {
+ auto it = instance_mapping.find(blas);
+ if (it != instance_mapping.end()) {
+ return it->second;
+ }
+ else {
+ int blas_index = (int)[all_blas count];
+ instance_mapping[blas] = blas_index;
+ if (@available(macos 12.0, *)) {
+ [all_blas addObject:blas->accel_struct];
+ }
+ return blas_index;
+ }
+ };
+
+ MTLResourceOptions storage_mode;
+ if (device.hasUnifiedMemory) {
+ storage_mode = MTLResourceStorageModeShared;
+ }
+ else {
+ storage_mode = MTLResourceStorageModeManaged;
+ }
+
+ size_t instance_size;
+ if (motion_blur) {
+ instance_size = sizeof(MTLAccelerationStructureMotionInstanceDescriptor);
+ }
+ else {
+ instance_size = sizeof(MTLAccelerationStructureUserIDInstanceDescriptor);
+ }
+
+ /* Allocate a GPU buffer for the instance data and populate it */
+ id<MTLBuffer> instanceBuf = [device newBufferWithLength:num_instances * instance_size
+ options:storage_mode];
+ id<MTLBuffer> motion_transforms_buf = nil;
+ MTLPackedFloat4x3 *motion_transforms = nullptr;
+ if (motion_blur && num_motion_transforms) {
+ motion_transforms_buf = [device
+ newBufferWithLength:num_motion_transforms * sizeof(MTLPackedFloat4x3)
+ options:storage_mode];
+ motion_transforms = (MTLPackedFloat4x3 *)motion_transforms_buf.contents;
+ }
+
+ uint32_t instance_index = 0;
+ uint32_t motion_transform_index = 0;
+ for (Object *ob : objects) {
+ /* Skip non-traceable objects */
+ if (!ob->is_traceable())
+ continue;
+
+ Geometry const *geom = ob->get_geometry();
+
+ BVHMetal const *blas = static_cast<BVHMetal const *>(geom->bvh);
+ uint32_t accel_struct_index = get_blas_index(blas);
+
+ /* Add some of the object visibility bits to the mask.
+ * __prim_visibility contains the combined visibility bits of all instances, so is not
+ * reliable if they differ between instances.
+ *
+ * METAL_WIP: OptiX visibility mask can only contain 8 bits, so have to trade-off here
+ * and select just a few important ones.
+ */
+ uint32_t mask = ob->visibility_for_tracing() & 0xFF;
+
+ /* Have to have at least one bit in the mask, or else instance would always be culled. */
+ if (0 == mask) {
+ mask = 0xFF;
+ }
+
+ /* Set user instance ID to object index */
+ int object_index = ob->get_device_index();
+ uint32_t user_id = uint32_t(object_index);
+
+ /* Bake into the appropriate descriptor */
+ if (motion_blur) {
+ MTLAccelerationStructureMotionInstanceDescriptor *instances =
+ (MTLAccelerationStructureMotionInstanceDescriptor *)[instanceBuf contents];
+ MTLAccelerationStructureMotionInstanceDescriptor &desc = instances[instance_index++];
+
+ desc.accelerationStructureIndex = accel_struct_index;
+ desc.userID = user_id;
+ desc.mask = mask;
+ desc.motionStartTime = 0.0f;
+ desc.motionEndTime = 1.0f;
+ desc.motionTransformsStartIndex = motion_transform_index;
+ desc.motionStartBorderMode = MTLMotionBorderModeVanish;
+ desc.motionEndBorderMode = MTLMotionBorderModeVanish;
+ desc.intersectionFunctionTableOffset = 0;
+
+ int key_count = ob->get_motion().size();
+ if (key_count) {
+ desc.motionTransformsCount = key_count;
+
+ Transform *keys = ob->get_motion().data();
+ for (int i = 0; i < key_count; i++) {
+ float *t = (float *)&motion_transforms[motion_transform_index++];
+ /* Transpose transform */
+ auto src = (float const *)&keys[i];
+ for (int i = 0; i < 12; i++) {
+ t[i] = src[(i / 3) + 4 * (i % 3)];
+ }
+ }
+ }
+ else {
+ desc.motionTransformsCount = 1;
+
+ float *t = (float *)&motion_transforms[motion_transform_index++];
+ if (ob->get_geometry()->is_instanced()) {
+ /* Transpose transform */
+ auto src = (float const *)&ob->get_tfm();
+ for (int i = 0; i < 12; i++) {
+ t[i] = src[(i / 3) + 4 * (i % 3)];
+ }
+ }
+ else {
+ /* Clear transform to identity matrix */
+ t[0] = t[4] = t[8] = 1.0f;
+ }
+ }
+ }
+ else {
+ MTLAccelerationStructureUserIDInstanceDescriptor *instances =
+ (MTLAccelerationStructureUserIDInstanceDescriptor *)[instanceBuf contents];
+ MTLAccelerationStructureUserIDInstanceDescriptor &desc = instances[instance_index++];
+
+ desc.accelerationStructureIndex = accel_struct_index;
+ desc.userID = user_id;
+ desc.mask = mask;
+ desc.intersectionFunctionTableOffset = 0;
+
+ float *t = (float *)&desc.transformationMatrix;
+ if (ob->get_geometry()->is_instanced()) {
+ /* Transpose transform */
+ auto src = (float const *)&ob->get_tfm();
+ for (int i = 0; i < 12; i++) {
+ t[i] = src[(i / 3) + 4 * (i % 3)];
+ }
+ }
+ else {
+ /* Clear transform to identity matrix */
+ t[0] = t[4] = t[8] = 1.0f;
+ }
+ }
+ }
+
+ if (storage_mode == MTLResourceStorageModeManaged) {
+ [instanceBuf didModifyRange:NSMakeRange(0, instanceBuf.length)];
+ if (motion_transforms_buf) {
+ [motion_transforms_buf didModifyRange:NSMakeRange(0, motion_transforms_buf.length)];
+ assert(num_motion_transforms == motion_transform_index);
+ }
+ }
+
+ MTLInstanceAccelerationStructureDescriptor *accelDesc =
+ [MTLInstanceAccelerationStructureDescriptor descriptor];
+ accelDesc.instanceCount = num_instances;
+ accelDesc.instanceDescriptorType = MTLAccelerationStructureInstanceDescriptorTypeUserID;
+ accelDesc.instanceDescriptorBuffer = instanceBuf;
+ accelDesc.instanceDescriptorBufferOffset = 0;
+ accelDesc.instanceDescriptorStride = instance_size;
+ accelDesc.instancedAccelerationStructures = all_blas;
+
+ if (motion_blur) {
+ accelDesc.instanceDescriptorType = MTLAccelerationStructureInstanceDescriptorTypeMotion;
+ accelDesc.motionTransformBuffer = motion_transforms_buf;
+ accelDesc.motionTransformCount = num_motion_transforms;
+ }
+
+ if (!use_fast_trace_bvh) {
+ accelDesc.usage |= (MTLAccelerationStructureUsageRefit |
+ MTLAccelerationStructureUsagePreferFastBuild);
+ }
+
+ MTLAccelerationStructureSizes accelSizes = [device
+ accelerationStructureSizesWithDescriptor:accelDesc];
+ id<MTLAccelerationStructure> accel = [device
+ newAccelerationStructureWithSize:accelSizes.accelerationStructureSize];
+ id<MTLBuffer> scratchBuf = [device newBufferWithLength:accelSizes.buildScratchBufferSize
+ options:MTLResourceStorageModePrivate];
+ id<MTLCommandBuffer> accelCommands = [queue commandBuffer];
+ id<MTLAccelerationStructureCommandEncoder> accelEnc =
+ [accelCommands accelerationStructureCommandEncoder];
+ if (refit) {
+ [accelEnc refitAccelerationStructure:accel_struct
+ descriptor:accelDesc
+ destination:accel
+ scratchBuffer:scratchBuf
+ scratchBufferOffset:0];
+ }
+ else {
+ [accelEnc buildAccelerationStructure:accel
+ descriptor:accelDesc
+ scratchBuffer:scratchBuf
+ scratchBufferOffset:0];
+ }
+ [accelEnc endEncoding];
+ [accelCommands commit];
+ [accelCommands waitUntilCompleted];
+
+ if (motion_transforms_buf) {
+ [motion_transforms_buf release];
+ }
+ [instanceBuf release];
+ [scratchBuf release];
+
+ uint64_t allocated_size = [accel allocatedSize];
+ stats.mem_alloc(allocated_size);
+
+ /* Cache top and bottom-level acceleration structs */
+ accel_struct = accel;
+ blas_array.clear();
+ blas_array.reserve(all_blas.count);
+ for (id<MTLAccelerationStructure> blas in all_blas) {
+ blas_array.push_back(blas);
+ }
+
+ return true;
+ }
+ return false;
+}
+
+bool BVHMetal::build(Progress &progress,
+ id<MTLDevice> device,
+ id<MTLCommandQueue> queue,
+ bool refit)
+{
+ if (@available(macos 12.0, *)) {
+ if (refit && params.bvh_type != BVH_TYPE_STATIC) {
+ assert(accel_struct);
+ }
+ else {
+ if (accel_struct) {
+ stats.mem_free(accel_struct.allocatedSize);
+ [accel_struct release];
+ accel_struct = nil;
+ }
+ }
+ }
+
+ if (!params.top_level) {
+ return build_BLAS(progress, device, queue, refit);
+ }
+ else {
+ return build_TLAS(progress, device, queue, refit);
+ }
+}
+
+CCL_NAMESPACE_END
+
+#endif /* WITH_METAL */
diff --git a/intern/cycles/device/metal/device.h b/intern/cycles/device/metal/device.h
new file mode 100644
index 00000000000..254fbfee42b
--- /dev/null
+++ b/intern/cycles/device/metal/device.h
@@ -0,0 +1,37 @@
+/*
+ * 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/string.h"
+#include "util/vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+class Device;
+class DeviceInfo;
+class Profiler;
+class Stats;
+
+bool device_metal_init();
+
+Device *device_metal_create(const DeviceInfo &info, Stats &stats, Profiler &profiler);
+
+void device_metal_info(vector<DeviceInfo> &devices);
+
+string device_metal_capabilities();
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/device/metal/device.mm b/intern/cycles/device/metal/device.mm
new file mode 100644
index 00000000000..bc893adea17
--- /dev/null
+++ b/intern/cycles/device/metal/device.mm
@@ -0,0 +1,136 @@
+/*
+ * 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.
+ */
+
+#ifdef WITH_METAL
+
+# include "device/metal/device.h"
+# include "device/metal/device_impl.h"
+
+#endif
+
+#include "util/debug.h"
+#include "util/set.h"
+#include "util/system.h"
+
+CCL_NAMESPACE_BEGIN
+
+#ifdef WITH_METAL
+
+Device *device_metal_create(const DeviceInfo &info, Stats &stats, Profiler &profiler)
+{
+ return new MetalDevice(info, stats, profiler);
+}
+
+bool device_metal_init()
+{
+ return true;
+}
+
+static int device_metal_get_num_devices_safe(uint32_t *num_devices)
+{
+ *num_devices = MTLCopyAllDevices().count;
+ return 0;
+}
+
+void device_metal_info(vector<DeviceInfo> &devices)
+{
+ uint32_t num_devices = 0;
+ device_metal_get_num_devices_safe(&num_devices);
+ if (num_devices == 0) {
+ return;
+ }
+
+ vector<MetalPlatformDevice> usable_devices;
+ MetalInfo::get_usable_devices(&usable_devices);
+ /* Devices are numbered consecutively across platforms. */
+ set<string> unique_ids;
+ int device_index = 0;
+ for (MetalPlatformDevice &device : usable_devices) {
+ /* Compute unique ID for persistent user preferences. */
+ const string &device_name = device.device_name;
+ string id = string("METAL_") + device_name;
+
+ /* Hardware ID might not be unique, add device number in that case. */
+ if (unique_ids.find(id) != unique_ids.end()) {
+ id += string_printf("_ID_%d", num_devices);
+ }
+ unique_ids.insert(id);
+
+ /* Create DeviceInfo. */
+ DeviceInfo info;
+ info.type = DEVICE_METAL;
+ info.description = string_remove_trademark(string(device_name));
+
+ /* Ensure unique naming on Apple Silicon / SoC devices which return the same string for CPU and
+ * GPU */
+ if (info.description == system_cpu_brand_string()) {
+ info.description += " (GPU)";
+ }
+
+ info.num = device_index;
+ /* We don't know if it's used for display, but assume it is. */
+ info.display_device = true;
+ info.denoisers = DENOISER_NONE;
+ info.id = id;
+
+ devices.push_back(info);
+ device_index++;
+ }
+}
+
+string device_metal_capabilities()
+{
+ string result = "";
+ string error_msg = "";
+ uint32_t num_devices = 0;
+ assert(device_metal_get_num_devices_safe(&num_devices));
+ if (num_devices == 0) {
+ return "No Metal devices found\n";
+ }
+ result += string_printf("Number of devices: %u\n", num_devices);
+
+ NSArray<id<MTLDevice>> *allDevices = MTLCopyAllDevices();
+ for (id<MTLDevice> device in allDevices) {
+ result += string_printf("\t\tDevice: %s\n", [device.name UTF8String]);
+ }
+
+ return result;
+}
+
+#else
+
+Device *device_metal_create(const DeviceInfo &info, Stats &stats, Profiler &profiler)
+{
+ return nullptr;
+}
+
+bool device_metal_init()
+{
+ return false;
+}
+
+void device_metal_info(vector<DeviceInfo> &devices)
+{
+}
+
+string device_metal_capabilities()
+{
+ return "";
+}
+
+#endif
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/device/metal/device_impl.h b/intern/cycles/device/metal/device_impl.h
new file mode 100644
index 00000000000..8d289beda13
--- /dev/null
+++ b/intern/cycles/device/metal/device_impl.h
@@ -0,0 +1,168 @@
+/*
+ * 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_METAL
+
+# include "bvh/bvh.h"
+# include "device/device.h"
+# include "device/metal/bvh.h"
+# include "device/metal/device.h"
+# include "device/metal/kernel.h"
+# include "device/metal/queue.h"
+# include "device/metal/util.h"
+
+# include <Metal/Metal.h>
+
+CCL_NAMESPACE_BEGIN
+
+class DeviceQueue;
+
+class MetalDevice : public Device {
+ public:
+ id<MTLDevice> mtlDevice = nil;
+ id<MTLLibrary> mtlLibrary[PSO_NUM] = {nil};
+ id<MTLArgumentEncoder> mtlBufferKernelParamsEncoder =
+ nil; /* encoder used for fetching device pointers from MTLBuffers */
+ id<MTLCommandQueue> mtlGeneralCommandQueue = nil;
+ id<MTLArgumentEncoder> mtlAncillaryArgEncoder =
+ nil; /* encoder used for fetching device pointers from MTLBuffers */
+ string source_used_for_compile[PSO_NUM];
+
+ KernelParamsMetal launch_params = {0};
+
+ /* MetalRT members ----------------------------------*/
+ BVHMetal *bvhMetalRT = nullptr;
+ bool motion_blur = false;
+ id<MTLArgumentEncoder> mtlASArgEncoder =
+ nil; /* encoder used for fetching device pointers from MTLAccelerationStructure */
+ /*---------------------------------------------------*/
+
+ string device_name;
+ MetalGPUVendor device_vendor;
+
+ uint kernel_features;
+ MTLResourceOptions default_storage_mode;
+ int max_threads_per_threadgroup;
+
+ int mtlDevId = 0;
+ bool first_error = true;
+
+ struct MetalMem {
+ device_memory *mem = nullptr;
+ int pointer_index = -1;
+ id<MTLBuffer> mtlBuffer = nil;
+ id<MTLTexture> mtlTexture = nil;
+ uint64_t offset = 0;
+ uint64_t size = 0;
+ void *hostPtr = nullptr;
+ bool use_UMA = false; /* If true, UMA memory in shared_pointer is being used. */
+ };
+ typedef map<device_memory *, unique_ptr<MetalMem>> MetalMemMap;
+ MetalMemMap metal_mem_map;
+ std::vector<id<MTLResource>> delayed_free_list;
+ std::recursive_mutex metal_mem_map_mutex;
+
+ /* Bindless Textures */
+ device_vector<TextureInfo> texture_info;
+ bool need_texture_info;
+ id<MTLArgumentEncoder> mtlTextureArgEncoder = nil;
+ id<MTLBuffer> texture_bindings_2d = nil;
+ id<MTLBuffer> texture_bindings_3d = nil;
+ std::vector<id<MTLTexture>> texture_slot_map;
+
+ MetalDeviceKernels kernels;
+ bool use_metalrt = false;
+ bool use_function_specialisation = false;
+
+ virtual BVHLayoutMask get_bvh_layout_mask() const override;
+
+ void set_error(const string &error) override;
+
+ MetalDevice(const DeviceInfo &info, Stats &stats, Profiler &profiler);
+
+ virtual ~MetalDevice();
+
+ bool support_device(const uint /*kernel_features*/);
+
+ bool check_peer_access(Device *peer_device) override;
+
+ bool use_adaptive_compilation();
+
+ string get_source(const uint kernel_features);
+
+ string compile_kernel(const uint kernel_features, const char *name);
+
+ virtual bool load_kernels(const uint kernel_features) override;
+
+ void reserve_local_memory(const uint kernel_features);
+
+ void init_host_memory();
+
+ void load_texture_info();
+
+ void erase_allocation(device_memory &mem);
+
+ virtual bool should_use_graphics_interop() override;
+
+ virtual unique_ptr<DeviceQueue> gpu_queue_create() override;
+
+ virtual void build_bvh(BVH *bvh, Progress &progress, bool refit) override;
+
+ /* ------------------------------------------------------------------ */
+ /* low-level memory management */
+
+ MetalMem *generic_alloc(device_memory &mem);
+
+ void generic_copy_to(device_memory &mem);
+
+ void generic_free(device_memory &mem);
+
+ void mem_alloc(device_memory &mem) override;
+
+ void mem_copy_to(device_memory &mem) override;
+
+ void mem_copy_from(device_memory &mem)
+ {
+ mem_copy_from(mem, -1, -1, -1, -1);
+ }
+ void mem_copy_from(device_memory &mem, size_t y, size_t w, size_t h, size_t elem) override;
+
+ void mem_zero(device_memory &mem) override;
+
+ void mem_free(device_memory &mem) override;
+
+ device_ptr mem_alloc_sub_ptr(device_memory &mem, size_t offset, size_t /*size*/) override;
+
+ virtual void const_copy_to(const char *name, void *host, size_t size) override;
+
+ void global_alloc(device_memory &mem);
+
+ void global_free(device_memory &mem);
+
+ void tex_alloc(device_texture &mem);
+
+ void tex_alloc_as_buffer(device_texture &mem);
+
+ void tex_free(device_texture &mem);
+
+ void flush_delayed_free_list();
+};
+
+CCL_NAMESPACE_END
+
+#endif
diff --git a/intern/cycles/device/metal/device_impl.mm b/intern/cycles/device/metal/device_impl.mm
new file mode 100644
index 00000000000..17acb2c94e4
--- /dev/null
+++ b/intern/cycles/device/metal/device_impl.mm
@@ -0,0 +1,1017 @@
+/*
+ * 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.
+ */
+
+#ifdef WITH_METAL
+
+# include "device/metal/device_impl.h"
+# include "device/metal/device.h"
+
+# include "util/debug.h"
+# include "util/md5.h"
+# include "util/path.h"
+
+CCL_NAMESPACE_BEGIN
+
+class MetalDevice;
+
+BVHLayoutMask MetalDevice::get_bvh_layout_mask() const
+{
+ return use_metalrt ? BVH_LAYOUT_METAL : BVH_LAYOUT_BVH2;
+}
+
+void MetalDevice::set_error(const string &error)
+{
+ static std::mutex s_error_mutex;
+ std::lock_guard<std::mutex> lock(s_error_mutex);
+
+ Device::set_error(error);
+
+ if (first_error) {
+ fprintf(stderr, "\nRefer to the Cycles GPU rendering documentation for possible solutions:\n");
+ fprintf(stderr,
+ "https://docs.blender.org/manual/en/latest/render/cycles/gpu_rendering.html\n\n");
+ first_error = false;
+ }
+}
+
+MetalDevice::MetalDevice(const DeviceInfo &info, Stats &stats, Profiler &profiler)
+ : Device(info, stats, profiler), texture_info(this, "__texture_info", MEM_GLOBAL)
+{
+ mtlDevId = info.num;
+
+ /* select chosen device */
+ vector<MetalPlatformDevice> usable_devices;
+ MetalInfo::get_usable_devices(&usable_devices);
+ if (usable_devices.size() == 0) {
+ set_error("Metal: no devices found.");
+ return;
+ }
+ assert(mtlDevId < usable_devices.size());
+ MetalPlatformDevice &platform_device = usable_devices[mtlDevId];
+ mtlDevice = platform_device.device_id;
+ device_name = platform_device.device_name;
+ device_vendor = MetalInfo::get_vendor_from_device_name(device_name);
+ assert(device_vendor != METAL_GPU_UNKNOWN);
+ metal_printf("Creating new Cycles device for Metal: %s\n", device_name.c_str());
+
+ /* determine default storage mode based on whether UMA is supported */
+
+ default_storage_mode = MTLResourceStorageModeManaged;
+
+ if (@available(macos 11.0, *)) {
+ if ([mtlDevice hasUnifiedMemory]) {
+ default_storage_mode = MTLResourceStorageModeShared;
+ init_host_memory();
+ }
+ }
+
+ texture_bindings_2d = [mtlDevice newBufferWithLength:4096 options:default_storage_mode];
+ texture_bindings_3d = [mtlDevice newBufferWithLength:4096 options:default_storage_mode];
+
+ stats.mem_alloc(texture_bindings_2d.allocatedSize + texture_bindings_3d.allocatedSize);
+
+ switch (device_vendor) {
+ default:
+ break;
+ case METAL_GPU_INTEL: {
+ max_threads_per_threadgroup = 64;
+ break;
+ }
+ case METAL_GPU_AMD: {
+ max_threads_per_threadgroup = 128;
+ break;
+ }
+ case METAL_GPU_APPLE: {
+ max_threads_per_threadgroup = 512;
+ break;
+ }
+ }
+
+ if (auto metalrt = getenv("CYCLES_METALRT")) {
+ use_metalrt = (atoi(metalrt) != 0);
+ }
+
+ MTLArgumentDescriptor *arg_desc_params = [[MTLArgumentDescriptor alloc] init];
+ arg_desc_params.dataType = MTLDataTypePointer;
+ arg_desc_params.access = MTLArgumentAccessReadOnly;
+ arg_desc_params.arrayLength = sizeof(KernelParamsMetal) / sizeof(device_ptr);
+ mtlBufferKernelParamsEncoder = [mtlDevice newArgumentEncoderWithArguments:@[ arg_desc_params ]];
+
+ MTLArgumentDescriptor *arg_desc_texture = [[MTLArgumentDescriptor alloc] init];
+ arg_desc_texture.dataType = MTLDataTypeTexture;
+ arg_desc_texture.access = MTLArgumentAccessReadOnly;
+ mtlTextureArgEncoder = [mtlDevice newArgumentEncoderWithArguments:@[ arg_desc_texture ]];
+
+ /* command queue for non-tracing work on the GPU */
+ mtlGeneralCommandQueue = [mtlDevice newCommandQueue];
+
+ /* Acceleration structure arg encoder, if needed */
+ if (@available(macos 12.0, *)) {
+ if (use_metalrt) {
+ MTLArgumentDescriptor *arg_desc_as = [[MTLArgumentDescriptor alloc] init];
+ arg_desc_as.dataType = MTLDataTypeInstanceAccelerationStructure;
+ arg_desc_as.access = MTLArgumentAccessReadOnly;
+ mtlASArgEncoder = [mtlDevice newArgumentEncoderWithArguments:@[ arg_desc_as ]];
+ [arg_desc_as release];
+ }
+ }
+
+ /* Build the arg encoder for the ancillary bindings */
+ {
+ NSMutableArray *ancillary_desc = [[NSMutableArray alloc] init];
+
+ int index = 0;
+ MTLArgumentDescriptor *arg_desc_tex = [[MTLArgumentDescriptor alloc] init];
+ arg_desc_tex.dataType = MTLDataTypePointer;
+ arg_desc_tex.access = MTLArgumentAccessReadOnly;
+
+ arg_desc_tex.index = index++;
+ [ancillary_desc addObject:[arg_desc_tex copy]]; /* metal_tex_2d */
+ arg_desc_tex.index = index++;
+ [ancillary_desc addObject:[arg_desc_tex copy]]; /* metal_tex_3d */
+
+ [arg_desc_tex release];
+
+ if (@available(macos 12.0, *)) {
+ if (use_metalrt) {
+ MTLArgumentDescriptor *arg_desc_as = [[MTLArgumentDescriptor alloc] init];
+ arg_desc_as.dataType = MTLDataTypeInstanceAccelerationStructure;
+ arg_desc_as.access = MTLArgumentAccessReadOnly;
+
+ MTLArgumentDescriptor *arg_desc_ift = [[MTLArgumentDescriptor alloc] init];
+ arg_desc_ift.dataType = MTLDataTypeIntersectionFunctionTable;
+ arg_desc_ift.access = MTLArgumentAccessReadOnly;
+
+ arg_desc_as.index = index++;
+ [ancillary_desc addObject:[arg_desc_as copy]]; /* accel_struct */
+ arg_desc_ift.index = index++;
+ [ancillary_desc addObject:[arg_desc_ift copy]]; /* ift_default */
+ arg_desc_ift.index = index++;
+ [ancillary_desc addObject:[arg_desc_ift copy]]; /* ift_shadow */
+ arg_desc_ift.index = index++;
+ [ancillary_desc addObject:[arg_desc_ift copy]]; /* ift_local */
+
+ [arg_desc_ift release];
+ [arg_desc_as release];
+ }
+ }
+
+ mtlAncillaryArgEncoder = [mtlDevice newArgumentEncoderWithArguments:ancillary_desc];
+
+ for (int i = 0; i < ancillary_desc.count; i++) {
+ [ancillary_desc[i] release];
+ }
+ [ancillary_desc release];
+ }
+ [arg_desc_params release];
+ [arg_desc_texture release];
+}
+
+MetalDevice::~MetalDevice()
+{
+ for (auto &tex : texture_slot_map) {
+ if (tex) {
+ [tex release];
+ tex = nil;
+ }
+ }
+ flush_delayed_free_list();
+
+ if (texture_bindings_2d) {
+ stats.mem_free(texture_bindings_2d.allocatedSize + texture_bindings_3d.allocatedSize);
+
+ [texture_bindings_2d release];
+ [texture_bindings_3d release];
+ }
+ [mtlTextureArgEncoder release];
+ [mtlBufferKernelParamsEncoder release];
+ [mtlASArgEncoder release];
+ [mtlAncillaryArgEncoder release];
+ [mtlGeneralCommandQueue release];
+ [mtlDevice release];
+
+ texture_info.free();
+}
+
+bool MetalDevice::support_device(const uint kernel_features /*requested_features*/)
+{
+ return true;
+}
+
+bool MetalDevice::check_peer_access(Device *peer_device)
+{
+ assert(0);
+ /* does peer access make sense? */
+ return false;
+}
+
+bool MetalDevice::use_adaptive_compilation()
+{
+ return DebugFlags().metal.adaptive_compile;
+}
+
+string MetalDevice::get_source(const uint kernel_features)
+{
+ string build_options;
+
+ if (use_adaptive_compilation()) {
+ build_options += " -D__KERNEL_FEATURES__=" + to_string(kernel_features);
+ }
+
+ if (use_metalrt) {
+ build_options += "-D__METALRT__ ";
+ if (motion_blur) {
+ build_options += "-D__METALRT_MOTION__ ";
+ }
+ }
+
+# ifdef WITH_CYCLES_DEBUG
+ build_options += "-D__KERNEL_DEBUG__ ";
+# endif
+
+ switch (device_vendor) {
+ default:
+ break;
+ case METAL_GPU_INTEL:
+ build_options += "-D__KERNEL_METAL_INTEL__ ";
+ break;
+ case METAL_GPU_AMD:
+ build_options += "-D__KERNEL_METAL_AMD__ ";
+ break;
+ case METAL_GPU_APPLE:
+ build_options += "-D__KERNEL_METAL_APPLE__ ";
+ break;
+ }
+
+ /* reformat -D defines list into compilable form */
+ vector<string> components;
+ string_replace(build_options, "-D", "");
+ string_split(components, build_options, " ");
+
+ string globalDefines;
+ for (const string &component : components) {
+ vector<string> assignments;
+ string_split(assignments, component, "=");
+ if (assignments.size() == 2)
+ globalDefines += string_printf(
+ "#define %s %s\n", assignments[0].c_str(), assignments[1].c_str());
+ else
+ globalDefines += string_printf("#define %s\n", assignments[0].c_str());
+ }
+
+ string source = globalDefines + "\n#include \"kernel/device/metal/kernel.metal\"\n";
+ source = path_source_replace_includes(source, path_get("source"));
+
+ metal_printf("Global defines:\n%s\n", globalDefines.c_str());
+
+ return source;
+}
+
+bool MetalDevice::load_kernels(const uint _kernel_features)
+{
+ kernel_features = _kernel_features;
+
+ /* check if GPU is supported */
+ if (!support_device(kernel_features))
+ return false;
+
+ /* Keep track of whether motion blur is enabled, so to enable/disable motion in BVH builds
+ * This is necessary since objects may be reported to have motion if the Vector pass is
+ * active, but may still need to be rendered without motion blur if that isn't active as well. */
+ motion_blur = kernel_features & KERNEL_FEATURE_OBJECT_MOTION;
+
+ NSError *error = NULL;
+
+ for (int i = 0; i < PSO_NUM; i++) {
+ if (mtlLibrary[i]) {
+ [mtlLibrary[i] release];
+ mtlLibrary[i] = nil;
+ }
+ }
+
+ MTLCompileOptions *options = [[MTLCompileOptions alloc] init];
+
+ options.fastMathEnabled = YES;
+ if (@available(macOS 12.0, *)) {
+ options.languageVersion = MTLLanguageVersion2_4;
+ }
+ else {
+ return false;
+ }
+
+ string metalsrc;
+
+ /* local helper: dump source to disk and return filepath */
+ auto dump_source = [&](int kernel_type) -> string {
+ string &source = source_used_for_compile[kernel_type];
+ string metalsrc = path_cache_get(path_join("kernels",
+ string_printf("%s.%s.metal",
+ kernel_type_as_string(kernel_type),
+ util_md5_string(source).c_str())));
+ path_write_text(metalsrc, source);
+ return metalsrc;
+ };
+
+ /* local helper: fetch the kernel source code, adjust it for specific PSO_.. kernel_type flavor,
+ * then compile it into a MTLLibrary */
+ auto fetch_and_compile_source = [&](int kernel_type) {
+ /* Record the source used to compile this library, for hash building later. */
+ string &source = source_used_for_compile[kernel_type];
+
+ switch (kernel_type) {
+ case PSO_GENERIC: {
+ source = get_source(kernel_features);
+ break;
+ }
+ case PSO_SPECIALISED: {
+ /* PSO_SPECIALISED derives from PSO_GENERIC */
+ string &generic_source = source_used_for_compile[PSO_GENERIC];
+ if (generic_source.empty()) {
+ generic_source = get_source(kernel_features);
+ }
+ source = "#define __KERNEL_METAL_USE_FUNCTION_SPECIALISATION__\n" + generic_source;
+ break;
+ }
+ default:
+ assert(0);
+ }
+
+ /* create MTLLibrary (front-end compilation) */
+ mtlLibrary[kernel_type] = [mtlDevice newLibraryWithSource:@(source.c_str())
+ options:options
+ error:&error];
+
+ bool do_source_dump = (getenv("CYCLES_METAL_DUMP_SOURCE") != nullptr);
+
+ if (!mtlLibrary[kernel_type] || do_source_dump) {
+ string metalsrc = dump_source(kernel_type);
+
+ if (!mtlLibrary[kernel_type]) {
+ NSString *err = [error localizedDescription];
+ set_error(string_printf("Failed to compile library:\n%s", [err UTF8String]));
+
+ return false;
+ }
+ }
+ return true;
+ };
+
+ fetch_and_compile_source(PSO_GENERIC);
+
+ if (use_function_specialisation) {
+ fetch_and_compile_source(PSO_SPECIALISED);
+ }
+
+ metal_printf("Front-end compilation finished\n");
+
+ bool result = kernels.load(this, PSO_GENERIC);
+
+ [options release];
+ reserve_local_memory(kernel_features);
+
+ return result;
+}
+
+void MetalDevice::reserve_local_memory(const uint kernel_features)
+{
+ /* METAL_WIP - implement this */
+}
+
+void MetalDevice::init_host_memory()
+{
+ /* METAL_WIP - implement this */
+}
+
+void MetalDevice::load_texture_info()
+{
+ if (need_texture_info) {
+ /* Unset flag before copying. */
+ need_texture_info = false;
+ texture_info.copy_to_device();
+
+ int num_textures = texture_info.size();
+
+ for (int tex = 0; tex < num_textures; tex++) {
+ uint64_t offset = tex * sizeof(void *);
+
+ id<MTLTexture> metal_texture = texture_slot_map[tex];
+ if (!metal_texture) {
+ [mtlTextureArgEncoder setArgumentBuffer:texture_bindings_2d offset:offset];
+ [mtlTextureArgEncoder setTexture:nil atIndex:0];
+ [mtlTextureArgEncoder setArgumentBuffer:texture_bindings_3d offset:offset];
+ [mtlTextureArgEncoder setTexture:nil atIndex:0];
+ }
+ else {
+ MTLTextureType type = metal_texture.textureType;
+ [mtlTextureArgEncoder setArgumentBuffer:texture_bindings_2d offset:offset];
+ [mtlTextureArgEncoder setTexture:type == MTLTextureType2D ? metal_texture : nil atIndex:0];
+ [mtlTextureArgEncoder setArgumentBuffer:texture_bindings_3d offset:offset];
+ [mtlTextureArgEncoder setTexture:type == MTLTextureType3D ? metal_texture : nil atIndex:0];
+ }
+ }
+ if (default_storage_mode == MTLResourceStorageModeManaged) {
+ [texture_bindings_2d didModifyRange:NSMakeRange(0, num_textures * sizeof(void *))];
+ [texture_bindings_3d didModifyRange:NSMakeRange(0, num_textures * sizeof(void *))];
+ }
+ }
+}
+
+void MetalDevice::erase_allocation(device_memory &mem)
+{
+ stats.mem_free(mem.device_size);
+ mem.device_pointer = 0;
+ mem.device_size = 0;
+
+ auto it = metal_mem_map.find(&mem);
+ if (it != metal_mem_map.end()) {
+ MetalMem *mmem = it->second.get();
+
+ /* blank out reference to MetalMem* in the launch params (fixes crash T94736) */
+ if (mmem->pointer_index >= 0) {
+ device_ptr *pointers = (device_ptr *)&launch_params;
+ pointers[mmem->pointer_index] = 0;
+ }
+ metal_mem_map.erase(it);
+ }
+}
+
+MetalDevice::MetalMem *MetalDevice::generic_alloc(device_memory &mem)
+{
+ size_t size = mem.memory_size();
+
+ mem.device_pointer = 0;
+
+ id<MTLBuffer> metal_buffer = nil;
+ if (size > 0) {
+ MTLResourceOptions options = default_storage_mode;
+ if (mem.type == MEM_DEVICE_ONLY) {
+ options = MTLResourceStorageModePrivate;
+ }
+
+ metal_buffer = [mtlDevice newBufferWithLength:size options:options];
+
+ if (!metal_buffer) {
+ set_error("System is out of GPU memory");
+ return nullptr;
+ }
+ }
+
+ if (mem.name) {
+ VLOG(2) << "Buffer allocate: " << mem.name << ", "
+ << string_human_readable_number(mem.memory_size()) << " bytes. ("
+ << string_human_readable_size(mem.memory_size()) << ")";
+ }
+
+ mem.device_size = metal_buffer.allocatedSize;
+ stats.mem_alloc(mem.device_size);
+
+ metal_buffer.label = [[NSString alloc] initWithFormat:@"%s", mem.name];
+
+ std::lock_guard<std::recursive_mutex> lock(metal_mem_map_mutex);
+
+ assert(metal_mem_map.count(&mem) == 0); /* assert against double-alloc */
+ MetalMem *mmem = new MetalMem;
+ metal_mem_map[&mem] = std::unique_ptr<MetalMem>(mmem);
+
+ mmem->mem = &mem;
+ mmem->mtlBuffer = metal_buffer;
+ mmem->offset = 0;
+ mmem->size = size;
+ if (mem.type != MEM_DEVICE_ONLY) {
+ mmem->hostPtr = [metal_buffer contents];
+ }
+ else {
+ mmem->hostPtr = nullptr;
+ }
+
+ /* encode device_pointer as (MetalMem*) in order to handle resource relocation and device pointer
+ * recalculation */
+ mem.device_pointer = device_ptr(mmem);
+
+ if (metal_buffer.storageMode == MTLResourceStorageModeShared) {
+ /* Replace host pointer with our host allocation. */
+
+ if (mem.host_pointer && mem.host_pointer != mmem->hostPtr) {
+ memcpy(mmem->hostPtr, mem.host_pointer, size);
+
+ mem.host_free();
+ mem.host_pointer = mmem->hostPtr;
+ }
+ mem.shared_pointer = mmem->hostPtr;
+ mem.shared_counter++;
+ mmem->use_UMA = true;
+ }
+ else {
+ mmem->use_UMA = false;
+ }
+
+ return mmem;
+}
+
+void MetalDevice::generic_copy_to(device_memory &mem)
+{
+ if (!mem.host_pointer || !mem.device_pointer) {
+ return;
+ }
+
+ std::lock_guard<std::recursive_mutex> lock(metal_mem_map_mutex);
+ if (!metal_mem_map.at(&mem)->use_UMA || mem.host_pointer != mem.shared_pointer) {
+ MetalMem &mmem = *metal_mem_map.at(&mem);
+ memcpy(mmem.hostPtr, mem.host_pointer, mem.memory_size());
+ if (mmem.mtlBuffer.storageMode == MTLStorageModeManaged) {
+ [mmem.mtlBuffer didModifyRange:NSMakeRange(0, mem.memory_size())];
+ }
+ }
+}
+
+void MetalDevice::generic_free(device_memory &mem)
+{
+ if (mem.device_pointer) {
+ std::lock_guard<std::recursive_mutex> lock(metal_mem_map_mutex);
+ MetalMem &mmem = *metal_mem_map.at(&mem);
+ size_t size = mmem.size;
+
+ /* If mmem.use_uma is true, reference counting is used
+ * to safely free memory. */
+
+ bool free_mtlBuffer = false;
+
+ if (mmem.use_UMA) {
+ assert(mem.shared_pointer);
+ if (mem.shared_pointer) {
+ assert(mem.shared_counter > 0);
+ if (--mem.shared_counter == 0) {
+ free_mtlBuffer = true;
+ }
+ }
+ }
+ else {
+ free_mtlBuffer = true;
+ }
+
+ if (free_mtlBuffer) {
+ if (mem.host_pointer && mem.host_pointer == mem.shared_pointer) {
+ /* Safely move the device-side data back to the host before it is freed. */
+ mem.host_pointer = mem.host_alloc(size);
+ memcpy(mem.host_pointer, mem.shared_pointer, size);
+ mmem.use_UMA = false;
+ }
+
+ mem.shared_pointer = 0;
+
+ /* Free device memory. */
+ delayed_free_list.push_back(mmem.mtlBuffer);
+ mmem.mtlBuffer = nil;
+ }
+
+ erase_allocation(mem);
+ }
+}
+
+void MetalDevice::mem_alloc(device_memory &mem)
+{
+ if (mem.type == MEM_TEXTURE) {
+ assert(!"mem_alloc not supported for textures.");
+ }
+ else if (mem.type == MEM_GLOBAL) {
+ generic_alloc(mem);
+ }
+ else {
+ generic_alloc(mem);
+ }
+}
+
+void MetalDevice::mem_copy_to(device_memory &mem)
+{
+ if (mem.type == MEM_GLOBAL) {
+ global_free(mem);
+ global_alloc(mem);
+ }
+ else if (mem.type == MEM_TEXTURE) {
+ tex_free((device_texture &)mem);
+ tex_alloc((device_texture &)mem);
+ }
+ else {
+ if (!mem.device_pointer) {
+ generic_alloc(mem);
+ }
+ generic_copy_to(mem);
+ }
+}
+
+void MetalDevice::mem_copy_from(device_memory &mem, size_t y, size_t w, size_t h, size_t elem)
+{
+ if (mem.host_pointer) {
+
+ bool subcopy = (w >= 0 && h >= 0);
+ const size_t size = subcopy ? (elem * w * h) : mem.memory_size();
+ const size_t offset = subcopy ? (elem * y * w) : 0;
+
+ if (mem.device_pointer) {
+ std::lock_guard<std::recursive_mutex> lock(metal_mem_map_mutex);
+ MetalMem &mmem = *metal_mem_map.at(&mem);
+
+ if ([mmem.mtlBuffer storageMode] == MTLStorageModeManaged) {
+
+ id<MTLCommandBuffer> cmdBuffer = [mtlGeneralCommandQueue commandBuffer];
+ id<MTLBlitCommandEncoder> blitEncoder = [cmdBuffer blitCommandEncoder];
+ [blitEncoder synchronizeResource:mmem.mtlBuffer];
+ [blitEncoder endEncoding];
+ [cmdBuffer commit];
+ [cmdBuffer waitUntilCompleted];
+ }
+
+ if (mem.host_pointer != mmem.hostPtr) {
+ memcpy((uchar *)mem.host_pointer + offset, (uchar *)mmem.hostPtr + offset, size);
+ }
+ }
+ else {
+ memset((char *)mem.host_pointer + offset, 0, size);
+ }
+ }
+}
+
+void MetalDevice::mem_zero(device_memory &mem)
+{
+ if (!mem.device_pointer) {
+ mem_alloc(mem);
+ }
+ if (!mem.device_pointer) {
+ return;
+ }
+
+ size_t size = mem.memory_size();
+ std::lock_guard<std::recursive_mutex> lock(metal_mem_map_mutex);
+ MetalMem &mmem = *metal_mem_map.at(&mem);
+ memset(mmem.hostPtr, 0, size);
+ if ([mmem.mtlBuffer storageMode] == MTLStorageModeManaged) {
+ [mmem.mtlBuffer didModifyRange:NSMakeRange(0, size)];
+ }
+}
+
+void MetalDevice::mem_free(device_memory &mem)
+{
+ if (mem.type == MEM_GLOBAL) {
+ global_free(mem);
+ }
+ else if (mem.type == MEM_TEXTURE) {
+ tex_free((device_texture &)mem);
+ }
+ else {
+ generic_free(mem);
+ }
+}
+
+device_ptr MetalDevice::mem_alloc_sub_ptr(device_memory &mem, size_t offset, size_t /*size*/)
+{
+ /* METAL_WIP - revive if necessary */
+ assert(0);
+ return 0;
+}
+
+void MetalDevice::const_copy_to(const char *name, void *host, size_t size)
+{
+ if (strcmp(name, "__data") == 0) {
+ assert(size == sizeof(KernelData));
+ memcpy((uint8_t *)&launch_params + offsetof(KernelParamsMetal, data), host, size);
+ return;
+ }
+
+ auto update_launch_pointers =
+ [&](size_t offset, void *data, size_t data_size, size_t pointers_size) {
+ memcpy((uint8_t *)&launch_params + offset, data, data_size);
+
+ MetalMem **mmem = (MetalMem **)data;
+ int pointer_count = pointers_size / sizeof(device_ptr);
+ int pointer_index = offset / sizeof(device_ptr);
+ for (int i = 0; i < pointer_count; i++) {
+ if (mmem[i]) {
+ mmem[i]->pointer_index = pointer_index + i;
+ }
+ }
+ };
+
+ /* Update data storage pointers in launch parameters. */
+ if (strcmp(name, "__integrator_state") == 0) {
+ /* IntegratorStateGPU is contiguous pointers */
+ const size_t pointer_block_size = sizeof(IntegratorStateGPU);
+ update_launch_pointers(
+ offsetof(KernelParamsMetal, __integrator_state), host, size, pointer_block_size);
+ }
+# define KERNEL_TEX(data_type, tex_name) \
+ else if (strcmp(name, #tex_name) == 0) \
+ { \
+ update_launch_pointers(offsetof(KernelParamsMetal, tex_name), host, size, size); \
+ }
+# include "kernel/textures.h"
+# undef KERNEL_TEX
+}
+
+void MetalDevice::global_alloc(device_memory &mem)
+{
+ if (mem.is_resident(this)) {
+ generic_alloc(mem);
+ generic_copy_to(mem);
+ }
+
+ const_copy_to(mem.name, &mem.device_pointer, sizeof(mem.device_pointer));
+}
+
+void MetalDevice::global_free(device_memory &mem)
+{
+ if (mem.is_resident(this) && mem.device_pointer) {
+ generic_free(mem);
+ }
+}
+
+void MetalDevice::tex_alloc_as_buffer(device_texture &mem)
+{
+ generic_alloc(mem);
+ generic_copy_to(mem);
+
+ /* Resize once */
+ const uint slot = mem.slot;
+ if (slot >= texture_info.size()) {
+ /* Allocate some slots in advance, to reduce amount
+ * of re-allocations. */
+ texture_info.resize(round_up(slot + 1, 128));
+ }
+
+ mem.info.data = (uint64_t)mem.device_pointer;
+
+ /* Set Mapping and tag that we need to (re-)upload to device */
+ texture_info[slot] = mem.info;
+ need_texture_info = true;
+}
+
+void MetalDevice::tex_alloc(device_texture &mem)
+{
+ MTLStorageMode storage_mode = MTLStorageModeManaged;
+ if (@available(macos 10.15, *)) {
+ if ([mtlDevice hasUnifiedMemory] &&
+ device_vendor !=
+ METAL_GPU_INTEL) { /* Intel GPUs don't support MTLStorageModeShared for MTLTextures */
+ storage_mode = MTLStorageModeShared;
+ }
+ }
+
+ /* General variables for both architectures */
+ string bind_name = mem.name;
+ size_t dsize = datatype_size(mem.data_type);
+ size_t size = mem.memory_size();
+
+ /* sampler_index maps into the GPU's constant 'metal_samplers' array */
+ uint64_t sampler_index = mem.info.extension;
+ if (mem.info.interpolation != INTERPOLATION_CLOSEST) {
+ sampler_index += 3;
+ }
+
+ /* Image Texture Storage */
+ MTLPixelFormat format;
+ switch (mem.data_type) {
+ case TYPE_UCHAR: {
+ MTLPixelFormat formats[] = {MTLPixelFormatR8Unorm,
+ MTLPixelFormatRG8Unorm,
+ MTLPixelFormatInvalid,
+ MTLPixelFormatRGBA8Unorm};
+ format = formats[mem.data_elements - 1];
+ } break;
+ case TYPE_UINT16: {
+ MTLPixelFormat formats[] = {MTLPixelFormatR16Unorm,
+ MTLPixelFormatRG16Unorm,
+ MTLPixelFormatInvalid,
+ MTLPixelFormatRGBA16Unorm};
+ format = formats[mem.data_elements - 1];
+ } break;
+ case TYPE_UINT: {
+ MTLPixelFormat formats[] = {MTLPixelFormatR32Uint,
+ MTLPixelFormatRG32Uint,
+ MTLPixelFormatInvalid,
+ MTLPixelFormatRGBA32Uint};
+ format = formats[mem.data_elements - 1];
+ } break;
+ case TYPE_INT: {
+ MTLPixelFormat formats[] = {MTLPixelFormatR32Sint,
+ MTLPixelFormatRG32Sint,
+ MTLPixelFormatInvalid,
+ MTLPixelFormatRGBA32Sint};
+ format = formats[mem.data_elements - 1];
+ } break;
+ case TYPE_FLOAT: {
+ MTLPixelFormat formats[] = {MTLPixelFormatR32Float,
+ MTLPixelFormatRG32Float,
+ MTLPixelFormatInvalid,
+ MTLPixelFormatRGBA32Float};
+ format = formats[mem.data_elements - 1];
+ } break;
+ case TYPE_HALF: {
+ MTLPixelFormat formats[] = {MTLPixelFormatR16Float,
+ MTLPixelFormatRG16Float,
+ MTLPixelFormatInvalid,
+ MTLPixelFormatRGBA16Float};
+ format = formats[mem.data_elements - 1];
+ } break;
+ default:
+ assert(0);
+ return;
+ }
+
+ assert(format != MTLPixelFormatInvalid);
+
+ id<MTLTexture> mtlTexture = nil;
+ size_t src_pitch = mem.data_width * dsize * mem.data_elements;
+
+ if (mem.data_depth > 1) {
+ /* 3D texture using array */
+ MTLTextureDescriptor *desc;
+
+ desc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:format
+ width:mem.data_width
+ height:mem.data_height
+ mipmapped:NO];
+
+ desc.storageMode = storage_mode;
+ desc.usage = MTLTextureUsageShaderRead;
+
+ desc.textureType = MTLTextureType3D;
+ desc.depth = mem.data_depth;
+
+ VLOG(2) << "Texture 3D allocate: " << mem.name << ", "
+ << string_human_readable_number(mem.memory_size()) << " bytes. ("
+ << string_human_readable_size(mem.memory_size()) << ")";
+
+ mtlTexture = [mtlDevice newTextureWithDescriptor:desc];
+ assert(mtlTexture);
+
+ if (!mtlTexture) {
+ return;
+ }
+
+ const size_t imageBytes = src_pitch * mem.data_height;
+ for (size_t d = 0; d < mem.data_depth; d++) {
+ const size_t offset = d * imageBytes;
+ [mtlTexture replaceRegion:MTLRegionMake3D(0, 0, d, mem.data_width, mem.data_height, 1)
+ mipmapLevel:0
+ slice:0
+ withBytes:(uint8_t *)mem.host_pointer + offset
+ bytesPerRow:src_pitch
+ bytesPerImage:0];
+ }
+ }
+ else if (mem.data_height > 0) {
+ /* 2D texture */
+ MTLTextureDescriptor *desc;
+
+ desc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:format
+ width:mem.data_width
+ height:mem.data_height
+ mipmapped:NO];
+
+ desc.storageMode = storage_mode;
+ desc.usage = MTLTextureUsageShaderRead;
+
+ VLOG(2) << "Texture 2D allocate: " << mem.name << ", "
+ << string_human_readable_number(mem.memory_size()) << " bytes. ("
+ << string_human_readable_size(mem.memory_size()) << ")";
+
+ mtlTexture = [mtlDevice newTextureWithDescriptor:desc];
+ assert(mtlTexture);
+
+ [mtlTexture replaceRegion:MTLRegionMake2D(0, 0, mem.data_width, mem.data_height)
+ mipmapLevel:0
+ withBytes:mem.host_pointer
+ bytesPerRow:src_pitch];
+ }
+ else {
+ assert(0);
+ /* 1D texture, using linear memory. */
+ }
+
+ mem.device_pointer = (device_ptr)mtlTexture;
+ mem.device_size = size;
+ stats.mem_alloc(size);
+
+ std::lock_guard<std::recursive_mutex> lock(metal_mem_map_mutex);
+ MetalMem *mmem = new MetalMem;
+ metal_mem_map[&mem] = std::unique_ptr<MetalMem>(mmem);
+ mmem->mem = &mem;
+ mmem->mtlTexture = mtlTexture;
+
+ /* Resize once */
+ const uint slot = mem.slot;
+ if (slot >= texture_info.size()) {
+ /* Allocate some slots in advance, to reduce amount
+ * of re-allocations. */
+ texture_info.resize(slot + 128);
+ texture_slot_map.resize(slot + 128);
+
+ ssize_t min_buffer_length = sizeof(void *) * texture_info.size();
+ if (!texture_bindings_2d || (texture_bindings_2d.length < min_buffer_length)) {
+ if (texture_bindings_2d) {
+ delayed_free_list.push_back(texture_bindings_2d);
+ delayed_free_list.push_back(texture_bindings_3d);
+
+ stats.mem_free(texture_bindings_2d.allocatedSize + texture_bindings_3d.allocatedSize);
+ }
+ texture_bindings_2d = [mtlDevice newBufferWithLength:min_buffer_length
+ options:default_storage_mode];
+ texture_bindings_3d = [mtlDevice newBufferWithLength:min_buffer_length
+ options:default_storage_mode];
+
+ stats.mem_alloc(texture_bindings_2d.allocatedSize + texture_bindings_3d.allocatedSize);
+ }
+ }
+
+ if (@available(macos 10.14, *)) {
+ /* Optimize the texture for GPU access. */
+ id<MTLCommandBuffer> commandBuffer = [mtlGeneralCommandQueue commandBuffer];
+ id<MTLBlitCommandEncoder> blitCommandEncoder = [commandBuffer blitCommandEncoder];
+ [blitCommandEncoder optimizeContentsForGPUAccess:mtlTexture];
+ [blitCommandEncoder endEncoding];
+ [commandBuffer commit];
+ }
+
+ /* Set Mapping and tag that we need to (re-)upload to device */
+ texture_slot_map[slot] = mtlTexture;
+ texture_info[slot] = mem.info;
+ need_texture_info = true;
+
+ texture_info[slot].data = uint64_t(slot) | (sampler_index << 32);
+}
+
+void MetalDevice::tex_free(device_texture &mem)
+{
+ if (metal_mem_map.count(&mem)) {
+ std::lock_guard<std::recursive_mutex> lock(metal_mem_map_mutex);
+ MetalMem &mmem = *metal_mem_map.at(&mem);
+
+ assert(texture_slot_map[mem.slot] == mmem.mtlTexture);
+ texture_slot_map[mem.slot] = nil;
+
+ if (mmem.mtlTexture) {
+ /* Free bindless texture. */
+ delayed_free_list.push_back(mmem.mtlTexture);
+ mmem.mtlTexture = nil;
+ }
+ erase_allocation(mem);
+ }
+}
+
+unique_ptr<DeviceQueue> MetalDevice::gpu_queue_create()
+{
+ return make_unique<MetalDeviceQueue>(this);
+}
+
+bool MetalDevice::should_use_graphics_interop()
+{
+ /* METAL_WIP - provide fast interop */
+ return false;
+}
+
+void MetalDevice::flush_delayed_free_list()
+{
+ /* free any Metal buffers that may have been freed by host while a command
+ * buffer was being generated. This function should be called after each
+ * completion of a command buffer */
+ std::lock_guard<std::recursive_mutex> lock(metal_mem_map_mutex);
+ for (auto &it : delayed_free_list) {
+ [it release];
+ }
+ delayed_free_list.clear();
+}
+
+void MetalDevice::build_bvh(BVH *bvh, Progress &progress, bool refit)
+{
+ if (bvh->params.bvh_layout == BVH_LAYOUT_BVH2) {
+ Device::build_bvh(bvh, progress, refit);
+ return;
+ }
+
+ BVHMetal *bvh_metal = static_cast<BVHMetal *>(bvh);
+ bvh_metal->motion_blur = motion_blur;
+ if (bvh_metal->build(progress, mtlDevice, mtlGeneralCommandQueue, refit)) {
+
+ if (@available(macos 11.0, *)) {
+ if (bvh->params.top_level) {
+ bvhMetalRT = bvh_metal;
+ }
+ }
+ }
+}
+
+CCL_NAMESPACE_END
+
+#endif
diff --git a/intern/cycles/device/metal/kernel.h b/intern/cycles/device/metal/kernel.h
new file mode 100644
index 00000000000..a4bfb30436d
--- /dev/null
+++ b/intern/cycles/device/metal/kernel.h
@@ -0,0 +1,170 @@
+/*
+ * 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_METAL
+
+# include "device/kernel.h"
+# include <Metal/Metal.h>
+
+CCL_NAMESPACE_BEGIN
+
+class MetalDevice;
+
+enum {
+ METALRT_FUNC_DEFAULT_TRI,
+ METALRT_FUNC_DEFAULT_BOX,
+ METALRT_FUNC_SHADOW_TRI,
+ METALRT_FUNC_SHADOW_BOX,
+ METALRT_FUNC_LOCAL_TRI,
+ METALRT_FUNC_LOCAL_BOX,
+ METALRT_FUNC_CURVE_RIBBON,
+ METALRT_FUNC_CURVE_RIBBON_SHADOW,
+ METALRT_FUNC_CURVE_ALL,
+ METALRT_FUNC_CURVE_ALL_SHADOW,
+ METALRT_FUNC_POINT,
+ METALRT_FUNC_POINT_SHADOW,
+ METALRT_FUNC_NUM
+};
+
+enum { METALRT_TABLE_DEFAULT, METALRT_TABLE_SHADOW, METALRT_TABLE_LOCAL, METALRT_TABLE_NUM };
+
+/* Pipeline State Object types */
+enum {
+ /* A kernel that can be used with all scenes, supporting all features.
+ * It is slow to compile, but only needs to be compiled once and is then
+ * cached for future render sessions. This allows a render to get underway
+ * on the GPU quickly.
+ */
+ PSO_GENERIC,
+
+ /* A kernel that is relatively quick to compile, but is specialized for the
+ * scene being rendered. It only contains the functionality and even baked in
+ * constants for values that means it needs to be recompiled whenever a
+ * dependent setting is changed. The render performance of this kernel is
+ * significantly faster though, and justifies the extra compile time.
+ */
+ /* METAL_WIP: This isn't used and will require more changes to enable. */
+ PSO_SPECIALISED,
+
+ PSO_NUM
+};
+
+const char *kernel_type_as_string(int kernel_type);
+
+struct MetalKernelPipeline {
+ void release()
+ {
+ if (pipeline) {
+ [pipeline release];
+ pipeline = nil;
+ if (@available(macOS 11.0, *)) {
+ for (int i = 0; i < METALRT_TABLE_NUM; i++) {
+ if (intersection_func_table[i]) {
+ [intersection_func_table[i] release];
+ intersection_func_table[i] = nil;
+ }
+ }
+ }
+ }
+ if (function) {
+ [function release];
+ function = nil;
+ }
+ if (@available(macOS 11.0, *)) {
+ for (int i = 0; i < METALRT_TABLE_NUM; i++) {
+ if (intersection_func_table[i]) {
+ [intersection_func_table[i] release];
+ }
+ }
+ }
+ }
+
+ bool loaded = false;
+ id<MTLFunction> function = nil;
+ id<MTLComputePipelineState> pipeline = nil;
+
+ API_AVAILABLE(macos(11.0))
+ id<MTLIntersectionFunctionTable> intersection_func_table[METALRT_TABLE_NUM] = {nil};
+};
+
+struct MetalKernelLoadDesc {
+ int pso_index = 0;
+ const char *function_name = nullptr;
+ int kernel_index = 0;
+ int threads_per_threadgroup = 0;
+ MTLFunctionConstantValues *constant_values = nullptr;
+ NSArray *linked_functions = nullptr;
+
+ struct IntersectorFunctions {
+ NSArray *defaults;
+ NSArray *shadow;
+ NSArray *local;
+ NSArray *operator[](int index) const
+ {
+ if (index == METALRT_TABLE_DEFAULT)
+ return defaults;
+ if (index == METALRT_TABLE_SHADOW)
+ return shadow;
+ return local;
+ }
+ } intersector_functions = {nullptr};
+};
+
+/* Metal kernel and associate occupancy information. */
+class MetalDeviceKernel {
+ public:
+ ~MetalDeviceKernel();
+
+ bool load(MetalDevice *device, MetalKernelLoadDesc const &desc, class MD5Hash const &md5);
+
+ void mark_loaded(int pso_index)
+ {
+ pso[pso_index].loaded = true;
+ }
+
+ int get_num_threads_per_block() const
+ {
+ return num_threads_per_block;
+ }
+ const MetalKernelPipeline &get_pso() const;
+
+ double load_duration = 0.0;
+
+ private:
+ MetalKernelPipeline pso[PSO_NUM];
+
+ int num_threads_per_block = 0;
+};
+
+/* Cache of Metal kernels for each DeviceKernel. */
+class MetalDeviceKernels {
+ public:
+ bool load(MetalDevice *device, int kernel_type);
+ bool available(DeviceKernel kernel) const;
+ const MetalDeviceKernel &get(DeviceKernel kernel) const;
+
+ MetalDeviceKernel kernels_[DEVICE_KERNEL_NUM];
+
+ id<MTLFunction> rt_intersection_funcs[PSO_NUM][METALRT_FUNC_NUM] = {{nil}};
+
+ string loaded_md5[PSO_NUM];
+};
+
+CCL_NAMESPACE_END
+
+#endif /* WITH_METAL */
diff --git a/intern/cycles/device/metal/kernel.mm b/intern/cycles/device/metal/kernel.mm
new file mode 100644
index 00000000000..e9bd1cea5df
--- /dev/null
+++ b/intern/cycles/device/metal/kernel.mm
@@ -0,0 +1,541 @@
+/*
+ * 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.
+ */
+
+#ifdef WITH_METAL
+
+# include "device/metal/kernel.h"
+# include "device/metal/device_impl.h"
+# include "util/md5.h"
+# include "util/path.h"
+# include "util/tbb.h"
+# include "util/time.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* limit to 2 MTLCompiler instances */
+int max_mtlcompiler_threads = 2;
+
+const char *kernel_type_as_string(int kernel_type)
+{
+ switch (kernel_type) {
+ case PSO_GENERIC:
+ return "PSO_GENERIC";
+ case PSO_SPECIALISED:
+ return "PSO_SPECIALISED";
+ default:
+ assert(0);
+ }
+ return "";
+}
+
+MetalDeviceKernel::~MetalDeviceKernel()
+{
+ for (int i = 0; i < PSO_NUM; i++) {
+ pso[i].release();
+ }
+}
+
+bool MetalDeviceKernel::load(MetalDevice *device,
+ MetalKernelLoadDesc const &desc_in,
+ MD5Hash const &md5)
+{
+ __block MetalKernelLoadDesc const desc(desc_in);
+ if (desc.kernel_index == DEVICE_KERNEL_INTEGRATOR_MEGAKERNEL) {
+ /* skip megakernel */
+ return true;
+ }
+
+ bool use_binary_archive = true;
+ if (getenv("CYCLES_METAL_DISABLE_BINARY_ARCHIVES")) {
+ use_binary_archive = false;
+ }
+
+ id<MTLBinaryArchive> archive = nil;
+ string metalbin_path;
+ if (use_binary_archive) {
+ NSProcessInfo *processInfo = [NSProcessInfo processInfo];
+ string osVersion = [[processInfo operatingSystemVersionString] UTF8String];
+ MD5Hash local_md5(md5);
+ local_md5.append(osVersion);
+ string metalbin_name = string(desc.function_name) + "." + local_md5.get_hex() +
+ to_string(desc.pso_index) + ".bin";
+ metalbin_path = path_cache_get(path_join("kernels", metalbin_name));
+ path_create_directories(metalbin_path);
+
+ if (path_exists(metalbin_path) && use_binary_archive) {
+ if (@available(macOS 11.0, *)) {
+ MTLBinaryArchiveDescriptor *archiveDesc = [[MTLBinaryArchiveDescriptor alloc] init];
+ archiveDesc.url = [NSURL fileURLWithPath:@(metalbin_path.c_str())];
+ archive = [device->mtlDevice newBinaryArchiveWithDescriptor:archiveDesc error:nil];
+ [archiveDesc release];
+ }
+ }
+ }
+
+ NSString *entryPoint = [@(desc.function_name) copy];
+
+ NSError *error = NULL;
+ if (@available(macOS 11.0, *)) {
+ MTLFunctionDescriptor *func_desc = [MTLIntersectionFunctionDescriptor functionDescriptor];
+ func_desc.name = entryPoint;
+ if (desc.constant_values) {
+ func_desc.constantValues = desc.constant_values;
+ }
+ pso[desc.pso_index].function = [device->mtlLibrary[desc.pso_index]
+ newFunctionWithDescriptor:func_desc
+ error:&error];
+ }
+ [entryPoint release];
+
+ if (pso[desc.pso_index].function == nil) {
+ NSString *err = [error localizedDescription];
+ string errors = [err UTF8String];
+
+ device->set_error(
+ string_printf("Error getting function \"%s\": %s", desc.function_name, errors.c_str()));
+ return false;
+ }
+
+ pso[desc.pso_index].function.label = [@(desc.function_name) copy];
+
+ __block MTLComputePipelineDescriptor *computePipelineStateDescriptor =
+ [[MTLComputePipelineDescriptor alloc] init];
+
+ computePipelineStateDescriptor.buffers[0].mutability = MTLMutabilityImmutable;
+ computePipelineStateDescriptor.buffers[1].mutability = MTLMutabilityImmutable;
+ computePipelineStateDescriptor.buffers[2].mutability = MTLMutabilityImmutable;
+
+ if (@available(macos 10.14, *)) {
+ computePipelineStateDescriptor.maxTotalThreadsPerThreadgroup = desc.threads_per_threadgroup;
+ }
+ computePipelineStateDescriptor.threadGroupSizeIsMultipleOfThreadExecutionWidth = true;
+
+ computePipelineStateDescriptor.computeFunction = pso[desc.pso_index].function;
+ if (@available(macOS 11.0, *)) {
+ /* Attach the additional functions to an MTLLinkedFunctions object */
+ if (desc.linked_functions) {
+ computePipelineStateDescriptor.linkedFunctions = [[MTLLinkedFunctions alloc] init];
+ computePipelineStateDescriptor.linkedFunctions.functions = desc.linked_functions;
+ }
+
+ computePipelineStateDescriptor.maxCallStackDepth = 1;
+ }
+
+ /* Create a new Compute pipeline state object */
+ MTLPipelineOption pipelineOptions = MTLPipelineOptionNone;
+
+ bool creating_new_archive = false;
+ if (@available(macOS 11.0, *)) {
+ if (use_binary_archive) {
+ if (!archive) {
+ MTLBinaryArchiveDescriptor *archiveDesc = [[MTLBinaryArchiveDescriptor alloc] init];
+ archiveDesc.url = nil;
+ archive = [device->mtlDevice newBinaryArchiveWithDescriptor:archiveDesc error:nil];
+ creating_new_archive = true;
+
+ double starttime = time_dt();
+
+ if (![archive addComputePipelineFunctionsWithDescriptor:computePipelineStateDescriptor
+ error:&error]) {
+ NSString *errStr = [error localizedDescription];
+ metal_printf("Failed to add PSO to archive:\n%s\n",
+ errStr ? [errStr UTF8String] : "nil");
+ }
+ else {
+ double duration = time_dt() - starttime;
+ metal_printf("%2d | %-55s | %7.2fs\n",
+ desc.kernel_index,
+ device_kernel_as_string((DeviceKernel)desc.kernel_index),
+ duration);
+
+ if (desc.pso_index == PSO_GENERIC) {
+ this->load_duration = duration;
+ }
+ }
+ }
+ computePipelineStateDescriptor.binaryArchives = [NSArray arrayWithObjects:archive, nil];
+ pipelineOptions = MTLPipelineOptionFailOnBinaryArchiveMiss;
+ }
+ }
+
+ double starttime = time_dt();
+
+ MTLNewComputePipelineStateWithReflectionCompletionHandler completionHandler = ^(
+ id<MTLComputePipelineState> computePipelineState,
+ MTLComputePipelineReflection *reflection,
+ NSError *error) {
+ bool recreate_archive = false;
+ if (computePipelineState == nil && archive && !creating_new_archive) {
+
+ assert(0);
+
+ NSString *errStr = [error localizedDescription];
+ metal_printf(
+ "Failed to create compute pipeline state \"%s\" from archive - attempting recreation... "
+ "(error: %s)\n",
+ device_kernel_as_string((DeviceKernel)desc.kernel_index),
+ errStr ? [errStr UTF8String] : "nil");
+ computePipelineState = [device->mtlDevice
+ newComputePipelineStateWithDescriptor:computePipelineStateDescriptor
+ options:MTLPipelineOptionNone
+ reflection:nullptr
+ error:&error];
+ recreate_archive = true;
+ }
+
+ double duration = time_dt() - starttime;
+
+ if (computePipelineState == nil) {
+ NSString *errStr = [error localizedDescription];
+ device->set_error(string_printf("Failed to create compute pipeline state \"%s\", error: \n",
+ device_kernel_as_string((DeviceKernel)desc.kernel_index)) +
+ (errStr ? [errStr UTF8String] : "nil"));
+ metal_printf("%2d | %-55s | %7.2fs | FAILED!\n",
+ desc.kernel_index,
+ device_kernel_as_string((DeviceKernel)desc.kernel_index),
+ duration);
+ return;
+ }
+
+ pso[desc.pso_index].pipeline = computePipelineState;
+ num_threads_per_block = round_down(computePipelineState.maxTotalThreadsPerThreadgroup,
+ computePipelineState.threadExecutionWidth);
+ num_threads_per_block = std::max(num_threads_per_block,
+ (int)computePipelineState.threadExecutionWidth);
+
+ if (!use_binary_archive) {
+ metal_printf("%2d | %-55s | %7.2fs\n",
+ desc.kernel_index,
+ device_kernel_as_string((DeviceKernel)desc.kernel_index),
+ duration);
+
+ if (desc.pso_index == PSO_GENERIC) {
+ this->load_duration = duration;
+ }
+ }
+
+ if (@available(macOS 11.0, *)) {
+ if (creating_new_archive || recreate_archive) {
+ if (![archive serializeToURL:[NSURL fileURLWithPath:@(metalbin_path.c_str())]
+ error:&error]) {
+ metal_printf("Failed to save binary archive, error:\n%s\n",
+ [[error localizedDescription] UTF8String]);
+ }
+ }
+ }
+
+ [computePipelineStateDescriptor release];
+ computePipelineStateDescriptor = nil;
+
+ if (device->use_metalrt && desc.linked_functions) {
+ for (int table = 0; table < METALRT_TABLE_NUM; table++) {
+ if (@available(macOS 11.0, *)) {
+ MTLIntersectionFunctionTableDescriptor *ift_desc =
+ [[MTLIntersectionFunctionTableDescriptor alloc] init];
+ ift_desc.functionCount = desc.intersector_functions[table].count;
+
+ pso[desc.pso_index].intersection_func_table[table] = [pso[desc.pso_index].pipeline
+ newIntersectionFunctionTableWithDescriptor:ift_desc];
+
+ /* Finally write the function handles into this pipeline's table */
+ for (int i = 0; i < 2; i++) {
+ id<MTLFunctionHandle> handle = [pso[desc.pso_index].pipeline
+ functionHandleWithFunction:desc.intersector_functions[table][i]];
+ [pso[desc.pso_index].intersection_func_table[table] setFunction:handle atIndex:i];
+ }
+ }
+ }
+ }
+
+ mark_loaded(desc.pso_index);
+ };
+
+ if (desc.pso_index == PSO_SPECIALISED) {
+ /* Asynchronous load */
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+ NSError *error;
+ id<MTLComputePipelineState> pipeline = [device->mtlDevice
+ newComputePipelineStateWithDescriptor:computePipelineStateDescriptor
+ options:pipelineOptions
+ reflection:nullptr
+ error:&error];
+ completionHandler(pipeline, nullptr, error);
+ });
+ }
+ else {
+ /* Block on load to ensure we continue with a valid kernel function */
+ id<MTLComputePipelineState> pipeline = [device->mtlDevice
+ newComputePipelineStateWithDescriptor:computePipelineStateDescriptor
+ options:pipelineOptions
+ reflection:nullptr
+ error:&error];
+ completionHandler(pipeline, nullptr, error);
+ }
+
+ return true;
+}
+
+const MetalKernelPipeline &MetalDeviceKernel::get_pso() const
+{
+ if (pso[PSO_SPECIALISED].loaded) {
+ return pso[PSO_SPECIALISED];
+ }
+
+ assert(pso[PSO_GENERIC].loaded);
+ return pso[PSO_GENERIC];
+}
+
+bool MetalDeviceKernels::load(MetalDevice *device, int kernel_type)
+{
+ bool any_error = false;
+
+ MD5Hash md5;
+
+ /* Build the function constant table */
+ MTLFunctionConstantValues *constant_values = nullptr;
+ if (kernel_type == PSO_SPECIALISED) {
+ constant_values = [MTLFunctionConstantValues new];
+
+# define KERNEL_FILM(_type, name) \
+ [constant_values setConstantValue:&data.film.name \
+ type:get_MTLDataType_##_type() \
+ atIndex:KernelData_film_##name]; \
+ md5.append((uint8_t *)&data.film.name, sizeof(data.film.name));
+
+# define KERNEL_BACKGROUND(_type, name) \
+ [constant_values setConstantValue:&data.background.name \
+ type:get_MTLDataType_##_type() \
+ atIndex:KernelData_background_##name]; \
+ md5.append((uint8_t *)&data.background.name, sizeof(data.background.name));
+
+# define KERNEL_INTEGRATOR(_type, name) \
+ [constant_values setConstantValue:&data.integrator.name \
+ type:get_MTLDataType_##_type() \
+ atIndex:KernelData_integrator_##name]; \
+ md5.append((uint8_t *)&data.integrator.name, sizeof(data.integrator.name));
+
+# define KERNEL_BVH(_type, name) \
+ [constant_values setConstantValue:&data.bvh.name \
+ type:get_MTLDataType_##_type() \
+ atIndex:KernelData_bvh_##name]; \
+ md5.append((uint8_t *)&data.bvh.name, sizeof(data.bvh.name));
+
+ /* METAL_WIP: populate constant_values based on KernelData */
+ assert(0);
+ /*
+ const KernelData &data = device->launch_params.data;
+ # include "kernel/types/background.h"
+ # include "kernel/types/bvh.h"
+ # include "kernel/types/film.h"
+ # include "kernel/types/integrator.h"
+ */
+ }
+
+ if (device->use_metalrt) {
+ if (@available(macOS 11.0, *)) {
+ /* create the id<MTLFunction> for each intersection function */
+ const char *function_names[] = {
+ "__anyhit__cycles_metalrt_visibility_test_tri",
+ "__anyhit__cycles_metalrt_visibility_test_box",
+ "__anyhit__cycles_metalrt_shadow_all_hit_tri",
+ "__anyhit__cycles_metalrt_shadow_all_hit_box",
+ "__anyhit__cycles_metalrt_local_hit_tri",
+ "__anyhit__cycles_metalrt_local_hit_box",
+ "__intersection__curve_ribbon",
+ "__intersection__curve_ribbon_shadow",
+ "__intersection__curve_all",
+ "__intersection__curve_all_shadow",
+ "__intersection__point",
+ "__intersection__point_shadow",
+ };
+ assert(sizeof(function_names) / sizeof(function_names[0]) == METALRT_FUNC_NUM);
+
+ MTLFunctionDescriptor *desc = [MTLIntersectionFunctionDescriptor functionDescriptor];
+ if (kernel_type == PSO_SPECIALISED) {
+ desc.constantValues = constant_values;
+ }
+ for (int i = 0; i < METALRT_FUNC_NUM; i++) {
+ const char *function_name = function_names[i];
+ desc.name = [@(function_name) copy];
+
+ NSError *error = NULL;
+ rt_intersection_funcs[kernel_type][i] = [device->mtlLibrary[kernel_type]
+ newFunctionWithDescriptor:desc
+ error:&error];
+
+ if (rt_intersection_funcs[kernel_type][i] == nil) {
+ NSString *err = [error localizedDescription];
+ string errors = [err UTF8String];
+
+ device->set_error(string_printf(
+ "Error getting intersection function \"%s\": %s", function_name, errors.c_str()));
+ any_error = true;
+ break;
+ }
+
+ rt_intersection_funcs[kernel_type][i].label = [@(function_name) copy];
+ }
+ }
+ }
+ md5.append(device->source_used_for_compile[kernel_type]);
+
+ string hash = md5.get_hex();
+ if (loaded_md5[kernel_type] == hash) {
+ return true;
+ }
+
+ if (!any_error) {
+ NSArray *table_functions[METALRT_TABLE_NUM] = {nil};
+ NSArray *function_list = nil;
+
+ if (device->use_metalrt) {
+ id<MTLFunction> curve_intersect_default = nil;
+ id<MTLFunction> curve_intersect_shadow = nil;
+ id<MTLFunction> point_intersect_default = nil;
+ id<MTLFunction> point_intersect_shadow = nil;
+ if (device->kernel_features & KERNEL_FEATURE_HAIR) {
+ /* Add curve intersection programs. */
+ if (device->kernel_features & KERNEL_FEATURE_HAIR_THICK) {
+ /* Slower programs for thick hair since that also slows down ribbons.
+ * Ideally this should not be needed. */
+ curve_intersect_default = rt_intersection_funcs[kernel_type][METALRT_FUNC_CURVE_ALL];
+ curve_intersect_shadow =
+ rt_intersection_funcs[kernel_type][METALRT_FUNC_CURVE_ALL_SHADOW];
+ }
+ else {
+ curve_intersect_default = rt_intersection_funcs[kernel_type][METALRT_FUNC_CURVE_RIBBON];
+ curve_intersect_shadow =
+ rt_intersection_funcs[kernel_type][METALRT_FUNC_CURVE_RIBBON_SHADOW];
+ }
+ }
+ if (device->kernel_features & KERNEL_FEATURE_POINTCLOUD) {
+ point_intersect_default = rt_intersection_funcs[kernel_type][METALRT_FUNC_POINT];
+ point_intersect_shadow = rt_intersection_funcs[kernel_type][METALRT_FUNC_POINT_SHADOW];
+ }
+ table_functions[METALRT_TABLE_DEFAULT] = [NSArray
+ arrayWithObjects:rt_intersection_funcs[kernel_type][METALRT_FUNC_DEFAULT_TRI],
+ curve_intersect_default ?
+ curve_intersect_default :
+ rt_intersection_funcs[kernel_type][METALRT_FUNC_DEFAULT_BOX],
+ point_intersect_default ?
+ point_intersect_default :
+ rt_intersection_funcs[kernel_type][METALRT_FUNC_DEFAULT_BOX],
+ nil];
+ table_functions[METALRT_TABLE_SHADOW] = [NSArray
+ arrayWithObjects:rt_intersection_funcs[kernel_type][METALRT_FUNC_SHADOW_TRI],
+ curve_intersect_shadow ?
+ curve_intersect_shadow :
+ rt_intersection_funcs[kernel_type][METALRT_FUNC_SHADOW_BOX],
+ point_intersect_shadow ?
+ point_intersect_shadow :
+ rt_intersection_funcs[kernel_type][METALRT_FUNC_SHADOW_BOX],
+ nil];
+ table_functions[METALRT_TABLE_LOCAL] = [NSArray
+ arrayWithObjects:rt_intersection_funcs[kernel_type][METALRT_FUNC_LOCAL_TRI],
+ rt_intersection_funcs[kernel_type][METALRT_FUNC_LOCAL_BOX],
+ rt_intersection_funcs[kernel_type][METALRT_FUNC_LOCAL_BOX],
+ nil];
+
+ NSMutableSet *unique_functions = [NSMutableSet
+ setWithArray:table_functions[METALRT_TABLE_DEFAULT]];
+ [unique_functions addObjectsFromArray:table_functions[METALRT_TABLE_SHADOW]];
+ [unique_functions addObjectsFromArray:table_functions[METALRT_TABLE_LOCAL]];
+
+ function_list = [[NSArray arrayWithArray:[unique_functions allObjects]]
+ sortedArrayUsingComparator:^NSComparisonResult(id<MTLFunction> f1, id<MTLFunction> f2) {
+ return [f1.label compare:f2.label];
+ }];
+
+ unique_functions = nil;
+ }
+
+ metal_printf("Starting %s \"cycles_metal_...\" pipeline builds\n",
+ kernel_type_as_string(kernel_type));
+
+ tbb::task_arena local_arena(max_mtlcompiler_threads);
+ local_arena.execute([&]() {
+ tbb::parallel_for(int(0), int(DEVICE_KERNEL_NUM), [&](int i) {
+ /* skip megakernel */
+ if (i == DEVICE_KERNEL_INTEGRATOR_MEGAKERNEL) {
+ return;
+ }
+
+ /* Only specialize kernels where it can make an impact. */
+ if (kernel_type == PSO_SPECIALISED) {
+ if (i < DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST ||
+ i > DEVICE_KERNEL_INTEGRATOR_MEGAKERNEL) {
+ return;
+ }
+ }
+
+ MetalDeviceKernel &kernel = kernels_[i];
+
+ const std::string function_name = std::string("cycles_metal_") +
+ device_kernel_as_string((DeviceKernel)i);
+ int threads_per_threadgroup = device->max_threads_per_threadgroup;
+ if (i > DEVICE_KERNEL_INTEGRATOR_MEGAKERNEL && i < DEVICE_KERNEL_INTEGRATOR_RESET) {
+ /* Always use 512 for the sorting kernels */
+ threads_per_threadgroup = 512;
+ }
+
+ NSArray *kernel_function_list = nil;
+
+ if (i == DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST ||
+ i == DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW ||
+ i == DEVICE_KERNEL_INTEGRATOR_INTERSECT_SUBSURFACE ||
+ i == DEVICE_KERNEL_INTEGRATOR_INTERSECT_VOLUME_STACK ||
+ i == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE) {
+ kernel_function_list = function_list;
+ }
+
+ MetalKernelLoadDesc desc;
+ desc.pso_index = kernel_type;
+ desc.kernel_index = i;
+ desc.linked_functions = kernel_function_list;
+ desc.intersector_functions.defaults = table_functions[METALRT_TABLE_DEFAULT];
+ desc.intersector_functions.shadow = table_functions[METALRT_TABLE_SHADOW];
+ desc.intersector_functions.local = table_functions[METALRT_TABLE_LOCAL];
+ desc.constant_values = constant_values;
+ desc.threads_per_threadgroup = threads_per_threadgroup;
+ desc.function_name = function_name.c_str();
+
+ bool success = kernel.load(device, desc, md5);
+
+ any_error |= !success;
+ });
+ });
+ }
+
+ bool loaded = !any_error;
+ if (loaded) {
+ loaded_md5[kernel_type] = hash;
+ }
+ return loaded;
+}
+
+const MetalDeviceKernel &MetalDeviceKernels::get(DeviceKernel kernel) const
+{
+ return kernels_[(int)kernel];
+}
+
+bool MetalDeviceKernels::available(DeviceKernel kernel) const
+{
+ return kernels_[(int)kernel].get_pso().function != nil;
+}
+
+CCL_NAMESPACE_END
+
+#endif /* WITH_METAL*/
diff --git a/intern/cycles/device/metal/queue.h b/intern/cycles/device/metal/queue.h
new file mode 100644
index 00000000000..64c8bb79c49
--- /dev/null
+++ b/intern/cycles/device/metal/queue.h
@@ -0,0 +1,99 @@
+/*
+ * 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_METAL
+
+# include "device/kernel.h"
+# include "device/memory.h"
+# include "device/queue.h"
+
+# include "device/metal/util.h"
+# include "kernel/device/metal/globals.h"
+
+# define metal_printf VLOG(4) << string_printf
+
+CCL_NAMESPACE_BEGIN
+
+class MetalDevice;
+
+/* Base class for Metal queues. */
+class MetalDeviceQueue : public DeviceQueue {
+ public:
+ MetalDeviceQueue(MetalDevice *device);
+ ~MetalDeviceQueue();
+
+ virtual int num_concurrent_states(const size_t) const override;
+ virtual int num_concurrent_busy_states() const override;
+
+ virtual void init_execution() override;
+
+ virtual bool enqueue(DeviceKernel kernel,
+ const int work_size,
+ DeviceKernelArguments const &args) override;
+
+ virtual bool synchronize() override;
+
+ virtual void zero_to_device(device_memory &mem) override;
+ virtual void copy_to_device(device_memory &mem) override;
+ virtual void copy_from_device(device_memory &mem) override;
+
+ virtual bool kernel_available(DeviceKernel kernel) const override;
+
+ protected:
+ void prepare_resources(DeviceKernel kernel);
+
+ id<MTLComputeCommandEncoder> get_compute_encoder(DeviceKernel kernel);
+ id<MTLBlitCommandEncoder> get_blit_encoder();
+
+ MetalDevice *metal_device;
+ MetalBufferPool temp_buffer_pool;
+
+ API_AVAILABLE(macos(11.0), ios(14.0))
+ MTLCommandBufferDescriptor *command_buffer_desc = nullptr;
+ id<MTLDevice> mtlDevice = nil;
+ id<MTLCommandQueue> mtlCommandQueue = nil;
+ id<MTLCommandBuffer> mtlCommandBuffer = nil;
+ id<MTLComputeCommandEncoder> mtlComputeEncoder = nil;
+ id<MTLBlitCommandEncoder> mtlBlitEncoder = nil;
+ API_AVAILABLE(macos(10.14), ios(14.0))
+ id<MTLSharedEvent> shared_event = nil;
+ API_AVAILABLE(macos(10.14), ios(14.0))
+ MTLSharedEventListener *shared_event_listener = nil;
+
+ dispatch_queue_t event_queue;
+ dispatch_semaphore_t wait_semaphore;
+
+ struct CopyBack {
+ void *host_pointer;
+ void *gpu_mem;
+ uint64_t size;
+ };
+ std::vector<CopyBack> copy_back_mem;
+
+ uint64_t shared_event_id;
+ uint64_t command_buffers_submitted = 0;
+ uint64_t command_buffers_completed = 0;
+ Stats &stats;
+
+ void close_compute_encoder();
+ void close_blit_encoder();
+};
+
+CCL_NAMESPACE_END
+
+#endif /* WITH_METAL */
diff --git a/intern/cycles/device/metal/queue.mm b/intern/cycles/device/metal/queue.mm
new file mode 100644
index 00000000000..d04df09f49a
--- /dev/null
+++ b/intern/cycles/device/metal/queue.mm
@@ -0,0 +1,610 @@
+/*
+ * 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.
+ */
+
+#ifdef WITH_METAL
+
+# include "device/metal/queue.h"
+
+# include "device/metal/device_impl.h"
+# include "device/metal/kernel.h"
+
+# include "util/path.h"
+# include "util/string.h"
+# include "util/time.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* MetalDeviceQueue */
+
+MetalDeviceQueue::MetalDeviceQueue(MetalDevice *device)
+ : DeviceQueue(device), metal_device(device), stats(device->stats)
+{
+ if (@available(macos 11.0, *)) {
+ command_buffer_desc = [[MTLCommandBufferDescriptor alloc] init];
+ command_buffer_desc.errorOptions = MTLCommandBufferErrorOptionEncoderExecutionStatus;
+ }
+
+ mtlDevice = device->mtlDevice;
+ mtlCommandQueue = [mtlDevice newCommandQueue];
+
+ if (@available(macos 10.14, *)) {
+ shared_event = [mtlDevice newSharedEvent];
+ shared_event_id = 1;
+
+ /* Shareable event listener */
+ event_queue = dispatch_queue_create("com.cycles.metal.event_queue", NULL);
+ shared_event_listener = [[MTLSharedEventListener alloc] initWithDispatchQueue:event_queue];
+ }
+
+ wait_semaphore = dispatch_semaphore_create(0);
+}
+
+MetalDeviceQueue::~MetalDeviceQueue()
+{
+ /* Tidying up here isn't really practical - we should expect and require the work
+ * queue to be empty here. */
+ assert(mtlCommandBuffer == nil);
+ assert(command_buffers_submitted == command_buffers_completed);
+
+ if (@available(macos 10.14, *)) {
+ [shared_event_listener release];
+ [shared_event release];
+ }
+
+ if (@available(macos 11.0, *)) {
+ [command_buffer_desc release];
+ }
+ if (mtlCommandQueue) {
+ [mtlCommandQueue release];
+ mtlCommandQueue = nil;
+ }
+}
+
+int MetalDeviceQueue::num_concurrent_states(const size_t /*state_size*/) const
+{
+ /* METAL_WIP */
+ /* TODO: compute automatically. */
+ /* TODO: must have at least num_threads_per_block. */
+ int result = 1048576;
+ if (metal_device->device_vendor == METAL_GPU_AMD) {
+ result *= 2;
+ }
+ else if (metal_device->device_vendor == METAL_GPU_APPLE) {
+ result *= 4;
+ }
+ return result;
+}
+
+int MetalDeviceQueue::num_concurrent_busy_states() const
+{
+ /* METAL_WIP */
+ /* TODO: compute automatically. */
+ int result = 65536;
+ if (metal_device->device_vendor == METAL_GPU_AMD) {
+ result *= 2;
+ }
+ else if (metal_device->device_vendor == METAL_GPU_APPLE) {
+ result *= 4;
+ }
+ return result;
+}
+
+void MetalDeviceQueue::init_execution()
+{
+ /* Synchronize all textures and memory copies before executing task. */
+ metal_device->load_texture_info();
+
+ synchronize();
+}
+
+bool MetalDeviceQueue::enqueue(DeviceKernel kernel,
+ const int work_size,
+ DeviceKernelArguments const &args)
+{
+ if (metal_device->have_error()) {
+ return false;
+ }
+
+ VLOG(3) << "Metal queue launch " << device_kernel_as_string(kernel) << ", work_size "
+ << work_size;
+
+ const MetalDeviceKernel &metal_kernel = metal_device->kernels.get(kernel);
+ const MetalKernelPipeline &metal_kernel_pso = metal_kernel.get_pso();
+
+ id<MTLComputeCommandEncoder> mtlComputeCommandEncoder = get_compute_encoder(kernel);
+
+ /* Determine size requirement for argument buffer. */
+ size_t arg_buffer_length = 0;
+ for (size_t i = 0; i < args.count; i++) {
+ size_t size_in_bytes = args.sizes[i];
+ arg_buffer_length = round_up(arg_buffer_length, size_in_bytes) + size_in_bytes;
+ }
+ /* 256 is the Metal offset alignment for constant address space bindings */
+ arg_buffer_length = round_up(arg_buffer_length, 256);
+
+ /* Globals placed after "vanilla" arguments. */
+ size_t globals_offsets = arg_buffer_length;
+ arg_buffer_length += sizeof(KernelParamsMetal);
+ arg_buffer_length = round_up(arg_buffer_length, 256);
+
+ /* Metal ancillary bindless pointers. */
+ size_t metal_offsets = arg_buffer_length;
+ arg_buffer_length += metal_device->mtlAncillaryArgEncoder.encodedLength;
+ arg_buffer_length = round_up(arg_buffer_length, metal_device->mtlAncillaryArgEncoder.alignment);
+
+ /* Temporary buffer used to prepare arg_buffer */
+ uint8_t *init_arg_buffer = (uint8_t *)alloca(arg_buffer_length);
+ memset(init_arg_buffer, 0, arg_buffer_length);
+
+ /* Prepare the non-pointer "enqueue" arguments */
+ size_t bytes_written = 0;
+ for (size_t i = 0; i < args.count; i++) {
+ size_t size_in_bytes = args.sizes[i];
+ bytes_written = round_up(bytes_written, size_in_bytes);
+ if (args.types[i] != DeviceKernelArguments::POINTER) {
+ memcpy(init_arg_buffer + bytes_written, args.values[i], size_in_bytes);
+ }
+ bytes_written += size_in_bytes;
+ }
+
+ /* Prepare any non-pointer (i.e. plain-old-data) KernelParamsMetal data */
+ /* The plain-old-data is contiguous, continuing to the end of KernelParamsMetal */
+ size_t plain_old_launch_data_offset = offsetof(KernelParamsMetal, __integrator_state) +
+ sizeof(IntegratorStateGPU);
+ size_t plain_old_launch_data_size = sizeof(KernelParamsMetal) - plain_old_launch_data_offset;
+ memcpy(init_arg_buffer + globals_offsets + plain_old_launch_data_offset,
+ (uint8_t *)&metal_device->launch_params + plain_old_launch_data_offset,
+ plain_old_launch_data_size);
+
+ /* Allocate an argument buffer. */
+ MTLResourceOptions arg_buffer_options = MTLResourceStorageModeManaged;
+ if (@available(macOS 11.0, *)) {
+ if ([mtlDevice hasUnifiedMemory]) {
+ arg_buffer_options = MTLResourceStorageModeShared;
+ }
+ }
+
+ id<MTLBuffer> arg_buffer = temp_buffer_pool.get_buffer(
+ mtlDevice, mtlCommandBuffer, arg_buffer_length, arg_buffer_options, init_arg_buffer, stats);
+
+ /* Encode the pointer "enqueue" arguments */
+ bytes_written = 0;
+ for (size_t i = 0; i < args.count; i++) {
+ size_t size_in_bytes = args.sizes[i];
+ bytes_written = round_up(bytes_written, size_in_bytes);
+ if (args.types[i] == DeviceKernelArguments::POINTER) {
+ [metal_device->mtlBufferKernelParamsEncoder setArgumentBuffer:arg_buffer
+ offset:bytes_written];
+ if (MetalDevice::MetalMem *mmem = *(MetalDevice::MetalMem **)args.values[i]) {
+ [mtlComputeCommandEncoder useResource:mmem->mtlBuffer
+ usage:MTLResourceUsageRead | MTLResourceUsageWrite];
+ [metal_device->mtlBufferKernelParamsEncoder setBuffer:mmem->mtlBuffer offset:0 atIndex:0];
+ }
+ else {
+ if (@available(macos 12.0, *)) {
+ [metal_device->mtlBufferKernelParamsEncoder setBuffer:nil offset:0 atIndex:0];
+ }
+ }
+ }
+ bytes_written += size_in_bytes;
+ }
+
+ /* Encode KernelParamsMetal buffers */
+ [metal_device->mtlBufferKernelParamsEncoder setArgumentBuffer:arg_buffer offset:globals_offsets];
+
+ /* this relies on IntegratorStateGPU layout being contiguous device_ptrs */
+ const size_t pointer_block_end = offsetof(KernelParamsMetal, __integrator_state) +
+ sizeof(IntegratorStateGPU);
+ for (size_t offset = 0; offset < pointer_block_end; offset += sizeof(device_ptr)) {
+ int pointer_index = offset / sizeof(device_ptr);
+ MetalDevice::MetalMem *mmem = *(
+ MetalDevice::MetalMem **)((uint8_t *)&metal_device->launch_params + offset);
+ if (mmem && (mmem->mtlBuffer || mmem->mtlTexture)) {
+ [metal_device->mtlBufferKernelParamsEncoder setBuffer:mmem->mtlBuffer
+ offset:0
+ atIndex:pointer_index];
+ }
+ else {
+ if (@available(macos 12.0, *)) {
+ [metal_device->mtlBufferKernelParamsEncoder setBuffer:nil offset:0 atIndex:pointer_index];
+ }
+ }
+ }
+ bytes_written = globals_offsets + sizeof(KernelParamsMetal);
+
+ /* Encode ancillaries */
+ [metal_device->mtlAncillaryArgEncoder setArgumentBuffer:arg_buffer offset:metal_offsets];
+ [metal_device->mtlAncillaryArgEncoder setBuffer:metal_device->texture_bindings_2d
+ offset:0
+ atIndex:0];
+ [metal_device->mtlAncillaryArgEncoder setBuffer:metal_device->texture_bindings_3d
+ offset:0
+ atIndex:1];
+ if (@available(macos 12.0, *)) {
+ if (metal_device->use_metalrt) {
+ if (metal_device->bvhMetalRT) {
+ id<MTLAccelerationStructure> accel_struct = metal_device->bvhMetalRT->accel_struct;
+ [metal_device->mtlAncillaryArgEncoder setAccelerationStructure:accel_struct atIndex:2];
+ }
+
+ for (int table = 0; table < METALRT_TABLE_NUM; table++) {
+ if (metal_kernel_pso.intersection_func_table[table]) {
+ [metal_kernel_pso.intersection_func_table[table] setBuffer:arg_buffer
+ offset:globals_offsets
+ atIndex:1];
+ [metal_device->mtlAncillaryArgEncoder
+ setIntersectionFunctionTable:metal_kernel_pso.intersection_func_table[table]
+ atIndex:3 + table];
+ [mtlComputeCommandEncoder useResource:metal_kernel_pso.intersection_func_table[table]
+ usage:MTLResourceUsageRead];
+ }
+ else {
+ [metal_device->mtlAncillaryArgEncoder setIntersectionFunctionTable:nil
+ atIndex:3 + table];
+ }
+ }
+ }
+ bytes_written = metal_offsets + metal_device->mtlAncillaryArgEncoder.encodedLength;
+ }
+
+ if (arg_buffer.storageMode == MTLStorageModeManaged) {
+ [arg_buffer didModifyRange:NSMakeRange(0, bytes_written)];
+ }
+
+ [mtlComputeCommandEncoder setBuffer:arg_buffer offset:0 atIndex:0];
+ [mtlComputeCommandEncoder setBuffer:arg_buffer offset:globals_offsets atIndex:1];
+ [mtlComputeCommandEncoder setBuffer:arg_buffer offset:metal_offsets atIndex:2];
+
+ if (metal_device->use_metalrt) {
+ if (@available(macos 12.0, *)) {
+
+ auto bvhMetalRT = metal_device->bvhMetalRT;
+ switch (kernel) {
+ case DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST:
+ case DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW:
+ case DEVICE_KERNEL_INTEGRATOR_INTERSECT_SUBSURFACE:
+ case DEVICE_KERNEL_INTEGRATOR_INTERSECT_VOLUME_STACK:
+ case DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE:
+ break;
+ default:
+ bvhMetalRT = nil;
+ break;
+ }
+
+ if (bvhMetalRT) {
+ /* Mark all Accelerations resources as used */
+ [mtlComputeCommandEncoder useResource:bvhMetalRT->accel_struct usage:MTLResourceUsageRead];
+ [mtlComputeCommandEncoder useResources:bvhMetalRT->blas_array.data()
+ count:bvhMetalRT->blas_array.size()
+ usage:MTLResourceUsageRead];
+ }
+ }
+ }
+
+ [mtlComputeCommandEncoder setComputePipelineState:metal_kernel_pso.pipeline];
+
+ /* Compute kernel launch parameters. */
+ const int num_threads_per_block = metal_kernel.get_num_threads_per_block();
+
+ int shared_mem_bytes = 0;
+
+ switch (kernel) {
+ case DEVICE_KERNEL_INTEGRATOR_QUEUED_PATHS_ARRAY:
+ case DEVICE_KERNEL_INTEGRATOR_QUEUED_SHADOW_PATHS_ARRAY:
+ case DEVICE_KERNEL_INTEGRATOR_ACTIVE_PATHS_ARRAY:
+ case DEVICE_KERNEL_INTEGRATOR_TERMINATED_PATHS_ARRAY:
+ case DEVICE_KERNEL_INTEGRATOR_SORTED_PATHS_ARRAY:
+ case DEVICE_KERNEL_INTEGRATOR_COMPACT_PATHS_ARRAY:
+ case DEVICE_KERNEL_INTEGRATOR_TERMINATED_SHADOW_PATHS_ARRAY:
+ case DEVICE_KERNEL_INTEGRATOR_COMPACT_SHADOW_PATHS_ARRAY:
+ /* See parallel_active_index.h for why this amount of shared memory is needed.
+ * Rounded up to 16 bytes for Metal */
+ shared_mem_bytes = round_up((num_threads_per_block + 1) * sizeof(int), 16);
+ [mtlComputeCommandEncoder setThreadgroupMemoryLength:shared_mem_bytes atIndex:0];
+ break;
+
+ default:
+ break;
+ }
+
+ MTLSize size_threadgroups_per_dispatch = MTLSizeMake(
+ divide_up(work_size, num_threads_per_block), 1, 1);
+ MTLSize size_threads_per_threadgroup = MTLSizeMake(num_threads_per_block, 1, 1);
+ [mtlComputeCommandEncoder dispatchThreadgroups:size_threadgroups_per_dispatch
+ threadsPerThreadgroup:size_threads_per_threadgroup];
+
+ [mtlCommandBuffer addCompletedHandler:^(id<MTLCommandBuffer> command_buffer) {
+ NSString *kernel_name = metal_kernel_pso.function.label;
+
+ /* Enhanced command buffer errors are only available in 11.0+ */
+ if (@available(macos 11.0, *)) {
+ if (command_buffer.status == MTLCommandBufferStatusError && command_buffer.error != nil) {
+ printf("CommandBuffer Failed: %s\n", [kernel_name UTF8String]);
+ NSArray<id<MTLCommandBufferEncoderInfo>> *encoderInfos = [command_buffer.error.userInfo
+ valueForKey:MTLCommandBufferEncoderInfoErrorKey];
+ if (encoderInfos != nil) {
+ for (id<MTLCommandBufferEncoderInfo> encoderInfo : encoderInfos) {
+ NSLog(@"%@", encoderInfo);
+ }
+ }
+ id<MTLLogContainer> logs = command_buffer.logs;
+ for (id<MTLFunctionLog> log in logs) {
+ NSLog(@"%@", log);
+ }
+ }
+ else if (command_buffer.error) {
+ printf("CommandBuffer Failed: %s\n", [kernel_name UTF8String]);
+ }
+ }
+ }];
+
+ return !(metal_device->have_error());
+}
+
+bool MetalDeviceQueue::synchronize()
+{
+ if (metal_device->have_error()) {
+ return false;
+ }
+
+ if (mtlComputeEncoder) {
+ close_compute_encoder();
+ }
+ close_blit_encoder();
+
+ if (mtlCommandBuffer) {
+ uint64_t shared_event_id = this->shared_event_id++;
+
+ if (@available(macos 10.14, *)) {
+ __block dispatch_semaphore_t block_sema = wait_semaphore;
+ [shared_event notifyListener:shared_event_listener
+ atValue:shared_event_id
+ block:^(id<MTLSharedEvent> sharedEvent, uint64_t value) {
+ dispatch_semaphore_signal(block_sema);
+ }];
+
+ [mtlCommandBuffer encodeSignalEvent:shared_event value:shared_event_id];
+ [mtlCommandBuffer commit];
+ dispatch_semaphore_wait(wait_semaphore, DISPATCH_TIME_FOREVER);
+ }
+
+ [mtlCommandBuffer release];
+
+ for (const CopyBack &mmem : copy_back_mem) {
+ memcpy((uchar *)mmem.host_pointer, (uchar *)mmem.gpu_mem, mmem.size);
+ }
+ copy_back_mem.clear();
+
+ temp_buffer_pool.process_command_buffer_completion(mtlCommandBuffer);
+ metal_device->flush_delayed_free_list();
+
+ mtlCommandBuffer = nil;
+ }
+
+ return !(metal_device->have_error());
+}
+
+void MetalDeviceQueue::zero_to_device(device_memory &mem)
+{
+ assert(mem.type != MEM_GLOBAL && mem.type != MEM_TEXTURE);
+
+ if (mem.memory_size() == 0) {
+ return;
+ }
+
+ /* Allocate on demand. */
+ if (mem.device_pointer == 0) {
+ metal_device->mem_alloc(mem);
+ }
+
+ /* Zero memory on device. */
+ assert(mem.device_pointer != 0);
+
+ std::lock_guard<std::recursive_mutex> lock(metal_device->metal_mem_map_mutex);
+ MetalDevice::MetalMem &mmem = *metal_device->metal_mem_map.at(&mem);
+ if (mmem.mtlBuffer) {
+ id<MTLBlitCommandEncoder> blitEncoder = get_blit_encoder();
+ [blitEncoder fillBuffer:mmem.mtlBuffer range:NSMakeRange(mmem.offset, mmem.size) value:0];
+ }
+ else {
+ metal_device->mem_zero(mem);
+ }
+}
+
+void MetalDeviceQueue::copy_to_device(device_memory &mem)
+{
+ if (mem.memory_size() == 0) {
+ return;
+ }
+
+ /* Allocate on demand. */
+ if (mem.device_pointer == 0) {
+ metal_device->mem_alloc(mem);
+ }
+
+ assert(mem.device_pointer != 0);
+ assert(mem.host_pointer != nullptr);
+
+ std::lock_guard<std::recursive_mutex> lock(metal_device->metal_mem_map_mutex);
+ auto result = metal_device->metal_mem_map.find(&mem);
+ if (result != metal_device->metal_mem_map.end()) {
+ if (mem.host_pointer == mem.shared_pointer) {
+ return;
+ }
+
+ MetalDevice::MetalMem &mmem = *result->second;
+ id<MTLBlitCommandEncoder> blitEncoder = get_blit_encoder();
+
+ id<MTLBuffer> buffer = temp_buffer_pool.get_buffer(mtlDevice,
+ mtlCommandBuffer,
+ mmem.size,
+ MTLResourceStorageModeShared,
+ mem.host_pointer,
+ stats);
+
+ [blitEncoder copyFromBuffer:buffer
+ sourceOffset:0
+ toBuffer:mmem.mtlBuffer
+ destinationOffset:mmem.offset
+ size:mmem.size];
+ }
+ else {
+ metal_device->mem_copy_to(mem);
+ }
+}
+
+void MetalDeviceQueue::copy_from_device(device_memory &mem)
+{
+ assert(mem.type != MEM_GLOBAL && mem.type != MEM_TEXTURE);
+
+ if (mem.memory_size() == 0) {
+ return;
+ }
+
+ assert(mem.device_pointer != 0);
+ assert(mem.host_pointer != nullptr);
+
+ std::lock_guard<std::recursive_mutex> lock(metal_device->metal_mem_map_mutex);
+ MetalDevice::MetalMem &mmem = *metal_device->metal_mem_map.at(&mem);
+ if (mmem.mtlBuffer) {
+ const size_t size = mem.memory_size();
+
+ if (mem.device_pointer) {
+ if ([mmem.mtlBuffer storageMode] == MTLStorageModeManaged) {
+ id<MTLBlitCommandEncoder> blitEncoder = get_blit_encoder();
+ [blitEncoder synchronizeResource:mmem.mtlBuffer];
+ }
+ if (mem.host_pointer != mmem.hostPtr) {
+ if (mtlCommandBuffer) {
+ copy_back_mem.push_back({mem.host_pointer, mmem.hostPtr, size});
+ }
+ else {
+ memcpy((uchar *)mem.host_pointer, (uchar *)mmem.hostPtr, size);
+ }
+ }
+ }
+ else {
+ memset((char *)mem.host_pointer, 0, size);
+ }
+ }
+ else {
+ metal_device->mem_copy_from(mem);
+ }
+}
+
+bool MetalDeviceQueue::kernel_available(DeviceKernel kernel) const
+{
+ return metal_device->kernels.available(kernel);
+}
+
+void MetalDeviceQueue::prepare_resources(DeviceKernel kernel)
+{
+ std::lock_guard<std::recursive_mutex> lock(metal_device->metal_mem_map_mutex);
+
+ /* declare resource usage */
+ for (auto &it : metal_device->metal_mem_map) {
+ device_memory *mem = it.first;
+
+ MTLResourceUsage usage = MTLResourceUsageRead;
+ if (mem->type != MEM_GLOBAL && mem->type != MEM_READ_ONLY && mem->type != MEM_TEXTURE) {
+ usage |= MTLResourceUsageWrite;
+ }
+
+ if (it.second->mtlBuffer) {
+ /* METAL_WIP - use array version (i.e. useResources) */
+ [mtlComputeEncoder useResource:it.second->mtlBuffer usage:usage];
+ }
+ else if (it.second->mtlTexture) {
+ /* METAL_WIP - use array version (i.e. useResources) */
+ [mtlComputeEncoder useResource:it.second->mtlTexture usage:usage | MTLResourceUsageSample];
+ }
+ }
+
+ /* ancillaries */
+ [mtlComputeEncoder useResource:metal_device->texture_bindings_2d usage:MTLResourceUsageRead];
+ [mtlComputeEncoder useResource:metal_device->texture_bindings_3d usage:MTLResourceUsageRead];
+}
+
+id<MTLComputeCommandEncoder> MetalDeviceQueue::get_compute_encoder(DeviceKernel kernel)
+{
+ bool concurrent = (kernel < DEVICE_KERNEL_INTEGRATOR_NUM);
+
+ if (@available(macos 10.14, *)) {
+ if (mtlComputeEncoder) {
+ if (mtlComputeEncoder.dispatchType == concurrent ? MTLDispatchTypeConcurrent :
+ MTLDispatchTypeSerial) {
+ /* declare usage of MTLBuffers etc */
+ prepare_resources(kernel);
+
+ return mtlComputeEncoder;
+ }
+ close_compute_encoder();
+ }
+
+ close_blit_encoder();
+
+ if (!mtlCommandBuffer) {
+ mtlCommandBuffer = [mtlCommandQueue commandBuffer];
+ [mtlCommandBuffer retain];
+ }
+
+ mtlComputeEncoder = [mtlCommandBuffer
+ computeCommandEncoderWithDispatchType:concurrent ? MTLDispatchTypeConcurrent :
+ MTLDispatchTypeSerial];
+
+ /* declare usage of MTLBuffers etc */
+ prepare_resources(kernel);
+ }
+
+ return mtlComputeEncoder;
+}
+
+id<MTLBlitCommandEncoder> MetalDeviceQueue::get_blit_encoder()
+{
+ if (mtlBlitEncoder) {
+ return mtlBlitEncoder;
+ }
+
+ if (mtlComputeEncoder) {
+ close_compute_encoder();
+ }
+
+ if (!mtlCommandBuffer) {
+ mtlCommandBuffer = [mtlCommandQueue commandBuffer];
+ [mtlCommandBuffer retain];
+ }
+
+ mtlBlitEncoder = [mtlCommandBuffer blitCommandEncoder];
+ return mtlBlitEncoder;
+}
+
+void MetalDeviceQueue::close_compute_encoder()
+{
+ [mtlComputeEncoder endEncoding];
+ mtlComputeEncoder = nil;
+}
+
+void MetalDeviceQueue::close_blit_encoder()
+{
+ if (mtlBlitEncoder) {
+ [mtlBlitEncoder endEncoding];
+ mtlBlitEncoder = nil;
+ }
+}
+
+CCL_NAMESPACE_END
+
+#endif /* WITH_METAL */
diff --git a/intern/cycles/device/metal/util.h b/intern/cycles/device/metal/util.h
new file mode 100644
index 00000000000..dbeb3a5d064
--- /dev/null
+++ b/intern/cycles/device/metal/util.h
@@ -0,0 +1,101 @@
+/*
+ * 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_METAL
+
+# include <Metal/Metal.h>
+# include <string>
+
+# include "device/metal/device.h"
+# include "device/metal/kernel.h"
+# include "device/queue.h"
+
+# include "util/thread.h"
+
+CCL_NAMESPACE_BEGIN
+
+enum MetalGPUVendor {
+ METAL_GPU_UNKNOWN = 0,
+ METAL_GPU_APPLE = 1,
+ METAL_GPU_AMD = 2,
+ METAL_GPU_INTEL = 3,
+};
+
+/* Retains a named MTLDevice for device enumeration. */
+struct MetalPlatformDevice {
+ MetalPlatformDevice(id<MTLDevice> device, const string &device_name)
+ : device_id(device), device_name(device_name)
+ {
+ [device_id retain];
+ }
+ ~MetalPlatformDevice()
+ {
+ [device_id release];
+ }
+ id<MTLDevice> device_id;
+ string device_name;
+};
+
+/* Contains static Metal helper functions. */
+struct MetalInfo {
+ static bool device_version_check(id<MTLDevice> device);
+ static void get_usable_devices(vector<MetalPlatformDevice> *usable_devices);
+ static MetalGPUVendor get_vendor_from_device_name(string const &device_name);
+
+ /* Platform information. */
+ static bool get_num_devices(uint32_t *num_platforms);
+ static uint32_t get_num_devices();
+
+ static bool get_device_name(id<MTLDevice> device_id, string *device_name);
+ static string get_device_name(id<MTLDevice> device_id);
+};
+
+/* Pool of MTLBuffers whose lifetime is linked to a single MTLCommandBuffer */
+class MetalBufferPool {
+ struct MetalBufferListEntry {
+ MetalBufferListEntry(id<MTLBuffer> buffer, id<MTLCommandBuffer> command_buffer)
+ : buffer(buffer), command_buffer(command_buffer)
+ {
+ }
+
+ MetalBufferListEntry() = delete;
+
+ id<MTLBuffer> buffer;
+ id<MTLCommandBuffer> command_buffer;
+ };
+ std::vector<MetalBufferListEntry> buffer_free_list;
+ std::vector<MetalBufferListEntry> buffer_in_use_list;
+ thread_mutex buffer_mutex;
+ size_t total_temp_mem_size = 0;
+
+ public:
+ MetalBufferPool() = default;
+ ~MetalBufferPool();
+
+ id<MTLBuffer> get_buffer(id<MTLDevice> device,
+ id<MTLCommandBuffer> command_buffer,
+ NSUInteger length,
+ MTLResourceOptions options,
+ const void *pointer,
+ Stats &stats);
+ void process_command_buffer_completion(id<MTLCommandBuffer> command_buffer);
+};
+
+CCL_NAMESPACE_END
+
+#endif /* WITH_METAL */
diff --git a/intern/cycles/device/metal/util.mm b/intern/cycles/device/metal/util.mm
new file mode 100644
index 00000000000..763a37cb503
--- /dev/null
+++ b/intern/cycles/device/metal/util.mm
@@ -0,0 +1,218 @@
+/*
+ * 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.
+ */
+
+#ifdef WITH_METAL
+
+# include "device/metal/util.h"
+# include "device/metal/device_impl.h"
+# include "util/md5.h"
+# include "util/path.h"
+# include "util/string.h"
+# include "util/time.h"
+
+# include <pwd.h>
+# include <sys/shm.h>
+# include <time.h>
+
+CCL_NAMESPACE_BEGIN
+
+MetalGPUVendor MetalInfo::get_vendor_from_device_name(string const &device_name)
+{
+ if (device_name.find("Intel") != string::npos) {
+ return METAL_GPU_INTEL;
+ }
+ else if (device_name.find("AMD") != string::npos) {
+ return METAL_GPU_AMD;
+ }
+ else if (device_name.find("Apple") != string::npos) {
+ return METAL_GPU_APPLE;
+ }
+ return METAL_GPU_UNKNOWN;
+}
+
+bool MetalInfo::device_version_check(id<MTLDevice> device)
+{
+ /* Metal Cycles doesn't work correctly on macOS versions older than 12.0 */
+ if (@available(macos 12.0, *)) {
+ MetalGPUVendor vendor = get_vendor_from_device_name([[device name] UTF8String]);
+
+ /* Metal Cycles works on Apple Silicon GPUs at present */
+ return (vendor == METAL_GPU_APPLE);
+ }
+
+ return false;
+}
+
+void MetalInfo::get_usable_devices(vector<MetalPlatformDevice> *usable_devices)
+{
+ static bool first_time = true;
+# define FIRST_VLOG(severity) \
+ if (first_time) \
+ VLOG(severity)
+
+ usable_devices->clear();
+
+ NSArray<id<MTLDevice>> *allDevices = MTLCopyAllDevices();
+ for (id<MTLDevice> device in allDevices) {
+ string device_name;
+ if (!get_device_name(device, &device_name)) {
+ FIRST_VLOG(2) << "Failed to get device name, ignoring.";
+ continue;
+ }
+
+ static const char *forceIntelStr = getenv("CYCLES_METAL_FORCE_INTEL");
+ bool forceIntel = forceIntelStr ? (atoi(forceIntelStr) != 0) : false;
+ if (forceIntel && device_name.find("Intel") == string::npos) {
+ FIRST_VLOG(2) << "CYCLES_METAL_FORCE_INTEL causing non-Intel device " << device_name
+ << " to be ignored.";
+ continue;
+ }
+
+ if (!device_version_check(device)) {
+ FIRST_VLOG(2) << "Ignoring device " << device_name << " due to too old compiler version.";
+ continue;
+ }
+ FIRST_VLOG(2) << "Adding new device " << device_name << ".";
+ string hardware_id;
+ usable_devices->push_back(MetalPlatformDevice(device, device_name));
+ }
+ first_time = false;
+}
+
+bool MetalInfo::get_num_devices(uint32_t *num_devices)
+{
+ *num_devices = MTLCopyAllDevices().count;
+ return true;
+}
+
+uint32_t MetalInfo::get_num_devices()
+{
+ uint32_t num_devices;
+ if (!get_num_devices(&num_devices)) {
+ return 0;
+ }
+ return num_devices;
+}
+
+bool MetalInfo::get_device_name(id<MTLDevice> device, string *platform_name)
+{
+ *platform_name = [device.name UTF8String];
+ return true;
+}
+
+string MetalInfo::get_device_name(id<MTLDevice> device)
+{
+ string platform_name;
+ if (!get_device_name(device, &platform_name)) {
+ return "";
+ }
+ return platform_name;
+}
+
+id<MTLBuffer> MetalBufferPool::get_buffer(id<MTLDevice> device,
+ id<MTLCommandBuffer> command_buffer,
+ NSUInteger length,
+ MTLResourceOptions options,
+ const void *pointer,
+ Stats &stats)
+{
+ id<MTLBuffer> buffer;
+
+ MTLStorageMode storageMode = MTLStorageMode((options & MTLResourceStorageModeMask) >>
+ MTLResourceStorageModeShift);
+ MTLCPUCacheMode cpuCacheMode = MTLCPUCacheMode((options & MTLResourceCPUCacheModeMask) >>
+ MTLResourceCPUCacheModeShift);
+
+ buffer_mutex.lock();
+ for (auto entry = buffer_free_list.begin(); entry != buffer_free_list.end(); entry++) {
+ MetalBufferListEntry bufferEntry = *entry;
+
+ /* Check if buffer matches size and storage mode and is old enough to reuse */
+ if (bufferEntry.buffer.length == length && storageMode == bufferEntry.buffer.storageMode &&
+ cpuCacheMode == bufferEntry.buffer.cpuCacheMode) {
+ buffer = bufferEntry.buffer;
+ buffer_free_list.erase(entry);
+ bufferEntry.command_buffer = command_buffer;
+ buffer_in_use_list.push_back(bufferEntry);
+ buffer_mutex.unlock();
+
+ /* Copy over data */
+ if (pointer) {
+ memcpy(buffer.contents, pointer, length);
+ if (bufferEntry.buffer.storageMode == MTLStorageModeManaged) {
+ [buffer didModifyRange:NSMakeRange(0, length)];
+ }
+ }
+
+ return buffer;
+ }
+ }
+ // NSLog(@"Creating buffer of length %lu (%lu)", length, frameCount);
+ if (pointer) {
+ buffer = [device newBufferWithBytes:pointer length:length options:options];
+ }
+ else {
+ buffer = [device newBufferWithLength:length options:options];
+ }
+
+ MetalBufferListEntry buffer_entry(buffer, command_buffer);
+
+ stats.mem_alloc(buffer.allocatedSize);
+
+ total_temp_mem_size += buffer.allocatedSize;
+ buffer_in_use_list.push_back(buffer_entry);
+ buffer_mutex.unlock();
+
+ return buffer;
+}
+
+void MetalBufferPool::process_command_buffer_completion(id<MTLCommandBuffer> command_buffer)
+{
+ assert(command_buffer);
+ thread_scoped_lock lock(buffer_mutex);
+ /* Release all buffers that have not been recently reused back into the free pool */
+ for (auto entry = buffer_in_use_list.begin(); entry != buffer_in_use_list.end();) {
+ MetalBufferListEntry buffer_entry = *entry;
+ if (buffer_entry.command_buffer == command_buffer) {
+ entry = buffer_in_use_list.erase(entry);
+ buffer_entry.command_buffer = nil;
+ buffer_free_list.push_back(buffer_entry);
+ }
+ else {
+ entry++;
+ }
+ }
+}
+
+MetalBufferPool::~MetalBufferPool()
+{
+ thread_scoped_lock lock(buffer_mutex);
+ /* Release all buffers that have not been recently reused */
+ for (auto entry = buffer_free_list.begin(); entry != buffer_free_list.end();) {
+ MetalBufferListEntry buffer_entry = *entry;
+
+ id<MTLBuffer> buffer = buffer_entry.buffer;
+ // NSLog(@"Releasing buffer of length %lu (%lu) (%lu outstanding)", buffer.length, frameCount,
+ // bufferFreeList.size());
+ total_temp_mem_size -= buffer.allocatedSize;
+ [buffer release];
+ entry = buffer_free_list.erase(entry);
+ }
+}
+
+CCL_NAMESPACE_END
+
+#endif /* WITH_METAL */
diff --git a/intern/cycles/device/multi/device.cpp b/intern/cycles/device/multi/device.cpp
index 4f995abf2c4..5ec3ef1b785 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
@@ -110,14 +109,6 @@ class MultiDevice : public Device {
return error_msg;
}
- virtual bool show_samples() const override
- {
- if (devices.size() > 1) {
- return false;
- }
- return devices.front().device->show_samples();
- }
-
virtual BVHLayoutMask get_bvh_layout_mask() const override
{
BVHLayoutMask bvh_layout_mask = BVH_LAYOUT_ALL;
@@ -133,11 +124,20 @@ class MultiDevice : public Device {
return BVH_LAYOUT_MULTI_OPTIX;
}
+ /* With multiple Metal devices, every device needs its own acceleration structure */
+ if (bvh_layout_mask == BVH_LAYOUT_METAL) {
+ return BVH_LAYOUT_MULTI_METAL;
+ }
+
/* When devices do not share a common BVH layout, fall back to creating one for each */
const BVHLayoutMask BVH_LAYOUT_OPTIX_EMBREE = (BVH_LAYOUT_OPTIX | BVH_LAYOUT_EMBREE);
if ((bvh_layout_mask_all & BVH_LAYOUT_OPTIX_EMBREE) == BVH_LAYOUT_OPTIX_EMBREE) {
return BVH_LAYOUT_MULTI_OPTIX_EMBREE;
}
+ const BVHLayoutMask BVH_LAYOUT_METAL_EMBREE = (BVH_LAYOUT_METAL | BVH_LAYOUT_EMBREE);
+ if ((bvh_layout_mask_all & BVH_LAYOUT_METAL_EMBREE) == BVH_LAYOUT_METAL_EMBREE) {
+ return BVH_LAYOUT_MULTI_METAL_EMBREE;
+ }
return bvh_layout_mask;
}
@@ -160,7 +160,9 @@ class MultiDevice : public Device {
}
assert(bvh->params.bvh_layout == BVH_LAYOUT_MULTI_OPTIX ||
- bvh->params.bvh_layout == BVH_LAYOUT_MULTI_OPTIX_EMBREE);
+ bvh->params.bvh_layout == BVH_LAYOUT_MULTI_METAL ||
+ bvh->params.bvh_layout == BVH_LAYOUT_MULTI_OPTIX_EMBREE ||
+ bvh->params.bvh_layout == BVH_LAYOUT_MULTI_METAL_EMBREE);
BVHMulti *const bvh_multi = static_cast<BVHMulti *>(bvh);
bvh_multi->sub_bvhs.resize(devices.size());
@@ -183,9 +185,14 @@ class MultiDevice : public Device {
BVHParams params = bvh->params;
if (bvh->params.bvh_layout == BVH_LAYOUT_MULTI_OPTIX)
params.bvh_layout = BVH_LAYOUT_OPTIX;
+ else if (bvh->params.bvh_layout == BVH_LAYOUT_MULTI_METAL)
+ params.bvh_layout = BVH_LAYOUT_METAL;
else if (bvh->params.bvh_layout == BVH_LAYOUT_MULTI_OPTIX_EMBREE)
params.bvh_layout = sub.device->info.type == DEVICE_OPTIX ? BVH_LAYOUT_OPTIX :
BVH_LAYOUT_EMBREE;
+ else if (bvh->params.bvh_layout == BVH_LAYOUT_MULTI_METAL_EMBREE)
+ params.bvh_layout = sub.device->info.type == DEVICE_METAL ? BVH_LAYOUT_METAL :
+ BVH_LAYOUT_EMBREE;
/* Skip building a bottom level acceleration structure for non-instanced geometry on Embree
* (since they are put into the top level directly, see bvh_embree.cpp) */
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 5f5eff53063..cb6c36d5ea6 100644
--- a/intern/cycles/device/optix/device_impl.cpp
+++ b/intern/cycles/device/optix/device_impl.cpp
@@ -20,45 +20,41 @@
# 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/pointcloud.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__
# include "kernel/device/optix/globals.h"
+# include <optix_denoiser_tiling.h>
+
CCL_NAMESPACE_BEGIN
OptiXDevice::Denoiser::Denoiser(OptiXDevice *device)
- : device(device), queue(device), state(device, "__denoiser_state")
-{
-}
-
-OptiXDevice::Denoiser::~Denoiser()
+ : device(device), queue(device), state(device, "__denoiser_state", true)
{
- const CUDAContextScope scope(device);
- if (optix_denoiser != nullptr) {
- optixDenoiserDestroy(optix_denoiser);
- }
}
OptiXDevice::OptiXDevice(const DeviceInfo &info, Stats &stats, Profiler &profiler)
: CUDADevice(info, stats, profiler),
sbt_data(this, "__sbt", MEM_READ_ONLY),
- launch_params(this, "__params"),
+ launch_params(this, "__params", false),
denoiser_(this)
{
/* Make the CUDA context current. */
@@ -90,6 +86,7 @@ OptiXDevice::OptiXDevice(const DeviceInfo &info, Stats &stats, Profiler &profile
};
# endif
if (DebugFlags().optix.use_debug) {
+ VLOG(1) << "Using OptiX debug mode.";
options.validationMode = OPTIX_DEVICE_CONTEXT_VALIDATION_MODE_ALL;
}
optix_assert(optixDeviceContextCreate(cuContext, &options, &context));
@@ -131,6 +128,11 @@ OptiXDevice::~OptiXDevice()
}
}
+ /* Make sure denoiser is destroyed before device context! */
+ if (denoiser_.optix_denoiser != nullptr) {
+ optixDenoiserDestroy(denoiser_.optix_denoiser);
+ }
+
optixDeviceContextDestroy(context);
}
@@ -209,18 +211,22 @@ bool OptiXDevice::load_kernels(const uint kernel_features)
}
else {
module_options.optLevel = OPTIX_COMPILE_OPTIMIZATION_LEVEL_3;
- module_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_LINEINFO;
+ module_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_NONE;
}
module_options.boundValues = nullptr;
module_options.numBoundValues = 0;
+# if OPTIX_ABI_VERSION >= 55
+ module_options.payloadTypes = nullptr;
+ module_options.numPayloadTypes = 0;
+# endif
OptixPipelineCompileOptions pipeline_options = {};
/* Default to no motion blur and two-level graph, since it is the fastest option. */
pipeline_options.usesMotionBlur = false;
pipeline_options.traversableGraphFlags =
OPTIX_TRAVERSABLE_GRAPH_FLAG_ALLOW_SINGLE_LEVEL_INSTANCING;
- pipeline_options.numPayloadValues = 6;
+ pipeline_options.numPayloadValues = 8;
pipeline_options.numAttributeValues = 2; /* u, v */
pipeline_options.exceptionFlags = OPTIX_EXCEPTION_FLAG_NONE;
pipeline_options.pipelineLaunchParamsVariableName = "__params"; /* See globals.h */
@@ -228,11 +234,18 @@ bool OptiXDevice::load_kernels(const uint kernel_features)
pipeline_options.usesPrimitiveTypeFlags = OPTIX_PRIMITIVE_TYPE_FLAGS_TRIANGLE;
if (kernel_features & KERNEL_FEATURE_HAIR) {
if (kernel_features & KERNEL_FEATURE_HAIR_THICK) {
+# if OPTIX_ABI_VERSION >= 55
+ pipeline_options.usesPrimitiveTypeFlags |= OPTIX_PRIMITIVE_TYPE_FLAGS_ROUND_CATMULLROM;
+# else
pipeline_options.usesPrimitiveTypeFlags |= OPTIX_PRIMITIVE_TYPE_FLAGS_ROUND_CUBIC_BSPLINE;
+# endif
}
else
pipeline_options.usesPrimitiveTypeFlags |= OPTIX_PRIMITIVE_TYPE_FLAGS_CUSTOM;
}
+ if (kernel_features & KERNEL_FEATURE_POINTCLOUD) {
+ pipeline_options.usesPrimitiveTypeFlags |= OPTIX_PRIMITIVE_TYPE_FLAGS_CUSTOM;
+ }
/* Keep track of whether motion blur is enabled, so to enable/disable motion in BVH builds
* This is necessary since objects may be reported to have motion if the Vector pass is
@@ -325,7 +338,13 @@ bool OptiXDevice::load_kernels(const uint kernel_features)
if (kernel_features & KERNEL_FEATURE_HAIR_THICK) {
/* Built-in thick curve intersection. */
OptixBuiltinISOptions builtin_options = {};
+# if OPTIX_ABI_VERSION >= 55
+ builtin_options.builtinISModuleType = OPTIX_PRIMITIVE_TYPE_ROUND_CATMULLROM;
+ builtin_options.buildFlags = OPTIX_BUILD_FLAG_PREFER_FAST_TRACE;
+ builtin_options.curveEndcapFlags = OPTIX_CURVE_ENDCAP_DEFAULT; /* Disable end-caps. */
+# else
builtin_options.builtinISModuleType = OPTIX_PRIMITIVE_TYPE_ROUND_CUBIC_BSPLINE;
+# endif
builtin_options.usesMotionBlur = false;
optix_assert(optixBuiltinISModuleGet(
@@ -357,6 +376,18 @@ bool OptiXDevice::load_kernels(const uint kernel_features)
}
}
+ /* Pointclouds */
+ if (kernel_features & KERNEL_FEATURE_POINTCLOUD) {
+ group_descs[PG_HITD_POINTCLOUD] = group_descs[PG_HITD];
+ group_descs[PG_HITD_POINTCLOUD].kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP;
+ group_descs[PG_HITD_POINTCLOUD].hitgroup.moduleIS = optix_module;
+ group_descs[PG_HITD_POINTCLOUD].hitgroup.entryFunctionNameIS = "__intersection__point";
+ group_descs[PG_HITS_POINTCLOUD] = group_descs[PG_HITS];
+ group_descs[PG_HITS_POINTCLOUD].kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP;
+ group_descs[PG_HITS_POINTCLOUD].hitgroup.moduleIS = optix_module;
+ group_descs[PG_HITS_POINTCLOUD].hitgroup.entryFunctionNameIS = "__intersection__point";
+ }
+
if (kernel_features & (KERNEL_FEATURE_SUBSURFACE | KERNEL_FEATURE_NODE_RAYTRACE)) {
/* Add hit group for local intersections. */
group_descs[PG_HITL].kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP;
@@ -377,9 +408,6 @@ bool OptiXDevice::load_kernels(const uint kernel_features)
group_descs[PG_CALL_SVM_BEVEL].callables.moduleDC = optix_module;
group_descs[PG_CALL_SVM_BEVEL].callables.entryFunctionNameDC =
"__direct_callable__svm_node_bevel";
- group_descs[PG_CALL_AO_PASS].kind = OPTIX_PROGRAM_GROUP_KIND_CALLABLES;
- group_descs[PG_CALL_AO_PASS].callables.moduleDC = optix_module;
- group_descs[PG_CALL_AO_PASS].callables.entryFunctionNameDC = "__direct_callable__ao_pass";
}
optix_assert(optixProgramGroupCreate(
@@ -407,6 +435,10 @@ bool OptiXDevice::load_kernels(const uint kernel_features)
stack_size[PG_HITD_MOTION].cssIS + stack_size[PG_HITD_MOTION].cssAH);
trace_css = std::max(trace_css,
stack_size[PG_HITS_MOTION].cssIS + stack_size[PG_HITS_MOTION].cssAH);
+ trace_css = std::max(
+ trace_css, stack_size[PG_HITD_POINTCLOUD].cssIS + stack_size[PG_HITD_POINTCLOUD].cssAH);
+ trace_css = std::max(
+ trace_css, stack_size[PG_HITS_POINTCLOUD].cssIS + stack_size[PG_HITS_POINTCLOUD].cssAH);
OptixPipelineLinkOptions link_options = {};
link_options.maxTraceDepth = 1;
@@ -415,7 +447,7 @@ bool OptiXDevice::load_kernels(const uint kernel_features)
link_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_FULL;
}
else {
- link_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_LINEINFO;
+ link_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_NONE;
}
if (kernel_features & KERNEL_FEATURE_NODE_RAYTRACE) {
@@ -432,6 +464,10 @@ bool OptiXDevice::load_kernels(const uint kernel_features)
pipeline_groups.push_back(groups[PG_HITD_MOTION]);
pipeline_groups.push_back(groups[PG_HITS_MOTION]);
}
+ if (kernel_features & KERNEL_FEATURE_POINTCLOUD) {
+ pipeline_groups.push_back(groups[PG_HITD_POINTCLOUD]);
+ pipeline_groups.push_back(groups[PG_HITS_POINTCLOUD]);
+ }
pipeline_groups.push_back(groups[PG_CALL_SVM_AO]);
pipeline_groups.push_back(groups[PG_CALL_SVM_BEVEL]);
@@ -471,6 +507,10 @@ bool OptiXDevice::load_kernels(const uint kernel_features)
pipeline_groups.push_back(groups[PG_HITD_MOTION]);
pipeline_groups.push_back(groups[PG_HITS_MOTION]);
}
+ if (kernel_features & KERNEL_FEATURE_POINTCLOUD) {
+ pipeline_groups.push_back(groups[PG_HITD_POINTCLOUD]);
+ pipeline_groups.push_back(groups[PG_HITS_POINTCLOUD]);
+ }
optix_assert(optixPipelineCreate(context,
&pipeline_options,
@@ -511,7 +551,7 @@ class OptiXDevice::DenoiseContext {
: denoise_params(task.params),
render_buffers(task.render_buffers),
buffer_params(task.buffer_params),
- guiding_buffer(device, "denoiser guiding passes buffer"),
+ guiding_buffer(device, "denoiser guiding passes buffer", true),
num_samples(task.num_samples)
{
num_input_passes = 1;
@@ -526,14 +566,28 @@ class OptiXDevice::DenoiseContext {
}
}
- const int num_guiding_passes = num_input_passes - 1;
+ if (denoise_params.temporally_stable) {
+ prev_output.device_pointer = render_buffers->buffer.device_pointer;
+
+ prev_output.offset = buffer_params.get_pass_offset(PASS_DENOISING_PREVIOUS);
+
+ prev_output.stride = buffer_params.stride;
+ prev_output.pass_stride = buffer_params.pass_stride;
+
+ num_input_passes += 1;
+ use_pass_flow = true;
+ pass_motion = buffer_params.get_pass_offset(PASS_MOTION);
+ }
+
+ use_guiding_passes = (num_input_passes - 1) > 0;
- if (num_guiding_passes) {
+ if (use_guiding_passes) {
if (task.allow_inplace_modification) {
guiding_params.device_pointer = render_buffers->buffer.device_pointer;
guiding_params.pass_albedo = pass_denoising_albedo;
guiding_params.pass_normal = pass_denoising_normal;
+ guiding_params.pass_flow = pass_motion;
guiding_params.stride = buffer_params.stride;
guiding_params.pass_stride = buffer_params.pass_stride;
@@ -548,6 +602,10 @@ class OptiXDevice::DenoiseContext {
guiding_params.pass_normal = guiding_params.pass_stride;
guiding_params.pass_stride += 3;
}
+ if (use_pass_flow) {
+ guiding_params.pass_flow = guiding_params.pass_stride;
+ guiding_params.pass_stride += 2;
+ }
guiding_params.stride = buffer_params.width;
@@ -565,6 +623,16 @@ class OptiXDevice::DenoiseContext {
RenderBuffers *render_buffers = nullptr;
const BufferParams &buffer_params;
+ /* Previous output. */
+ struct {
+ device_ptr device_pointer = 0;
+
+ int offset = PASS_UNUSED;
+
+ int stride = -1;
+ int pass_stride = -1;
+ } prev_output;
+
/* Device-side storage of the guiding passes. */
device_only_memory<float> guiding_buffer;
@@ -574,6 +642,7 @@ class OptiXDevice::DenoiseContext {
/* NOTE: Are only initialized when the corresponding guiding pass is enabled. */
int pass_albedo = PASS_UNUSED;
int pass_normal = PASS_UNUSED;
+ int pass_flow = PASS_UNUSED;
int stride = -1;
int pass_stride = -1;
@@ -581,8 +650,10 @@ class OptiXDevice::DenoiseContext {
/* Number of input passes. Including the color and extra auxiliary passes. */
int num_input_passes = 0;
+ bool use_guiding_passes = false;
bool use_pass_albedo = false;
bool use_pass_normal = false;
+ bool use_pass_flow = false;
int num_samples = 0;
@@ -591,6 +662,7 @@ class OptiXDevice::DenoiseContext {
/* NOTE: Are only initialized when the corresponding guiding pass is enabled. */
int pass_denoising_albedo = PASS_UNUSED;
int pass_denoising_normal = PASS_UNUSED;
+ int pass_motion = PASS_UNUSED;
/* For passes which don't need albedo channel for denoising we replace the actual albedo with
* the (0.5, 0.5, 0.5). This flag indicates that the real albedo pass has been replaced with
@@ -657,22 +729,24 @@ bool OptiXDevice::denoise_filter_guiding_preprocess(DenoiseContext &context)
const int work_size = buffer_params.width * buffer_params.height;
- void *args[] = {const_cast<device_ptr *>(&context.guiding_params.device_pointer),
- const_cast<int *>(&context.guiding_params.pass_stride),
- const_cast<int *>(&context.guiding_params.pass_albedo),
- const_cast<int *>(&context.guiding_params.pass_normal),
- &context.render_buffers->buffer.device_pointer,
- const_cast<int *>(&buffer_params.offset),
- const_cast<int *>(&buffer_params.stride),
- const_cast<int *>(&buffer_params.pass_stride),
- const_cast<int *>(&context.pass_sample_count),
- const_cast<int *>(&context.pass_denoising_albedo),
- const_cast<int *>(&context.pass_denoising_normal),
- const_cast<int *>(&buffer_params.full_x),
- const_cast<int *>(&buffer_params.full_y),
- const_cast<int *>(&buffer_params.width),
- const_cast<int *>(&buffer_params.height),
- const_cast<int *>(&context.num_samples)};
+ DeviceKernelArguments args(&context.guiding_params.device_pointer,
+ &context.guiding_params.pass_stride,
+ &context.guiding_params.pass_albedo,
+ &context.guiding_params.pass_normal,
+ &context.guiding_params.pass_flow,
+ &context.render_buffers->buffer.device_pointer,
+ &buffer_params.offset,
+ &buffer_params.stride,
+ &buffer_params.pass_stride,
+ &context.pass_sample_count,
+ &context.pass_denoising_albedo,
+ &context.pass_denoising_normal,
+ &context.pass_motion,
+ &buffer_params.full_x,
+ &buffer_params.full_y,
+ &buffer_params.width,
+ &buffer_params.height,
+ &context.num_samples);
return denoiser_.queue.enqueue(DEVICE_KERNEL_FILTER_GUIDING_PREPROCESS, work_size, args);
}
@@ -683,11 +757,11 @@ bool OptiXDevice::denoise_filter_guiding_set_fake_albedo(DenoiseContext &context
const int work_size = buffer_params.width * buffer_params.height;
- void *args[] = {const_cast<device_ptr *>(&context.guiding_params.device_pointer),
- const_cast<int *>(&context.guiding_params.pass_stride),
- const_cast<int *>(&context.guiding_params.pass_albedo),
- const_cast<int *>(&buffer_params.width),
- const_cast<int *>(&buffer_params.height)};
+ DeviceKernelArguments args(&context.guiding_params.device_pointer,
+ &context.guiding_params.pass_stride,
+ &context.guiding_params.pass_albedo,
+ &buffer_params.width,
+ &buffer_params.height);
return denoiser_.queue.enqueue(DEVICE_KERNEL_FILTER_GUIDING_SET_FAKE_ALBEDO, work_size, args);
}
@@ -712,7 +786,7 @@ void OptiXDevice::denoise_pass(DenoiseContext &context, PassType pass_type)
return;
}
}
- else if (!context.albedo_replaced_with_fake) {
+ else if (context.use_guiding_passes && !context.albedo_replaced_with_fake) {
context.albedo_replaced_with_fake = true;
if (!denoise_filter_guiding_set_fake_albedo(context)) {
LOG(ERROR) << "Error replacing real albedo with the fake one.";
@@ -768,7 +842,13 @@ void OptiXDevice::denoise_color_read(DenoiseContext &context, const DenoisePass
destination.num_components = 3;
destination.pixel_stride = context.buffer_params.pass_stride;
- pass_accessor.get_render_tile_pixels(context.render_buffers, context.buffer_params, destination);
+ BufferParams buffer_params = context.buffer_params;
+ buffer_params.window_x = 0;
+ buffer_params.window_y = 0;
+ buffer_params.window_width = buffer_params.width;
+ buffer_params.window_height = buffer_params.height;
+
+ pass_accessor.get_render_tile_pixels(context.render_buffers, buffer_params, destination);
}
bool OptiXDevice::denoise_filter_color_preprocess(DenoiseContext &context, const DenoisePass &pass)
@@ -777,15 +857,15 @@ bool OptiXDevice::denoise_filter_color_preprocess(DenoiseContext &context, const
const int work_size = buffer_params.width * buffer_params.height;
- void *args[] = {&context.render_buffers->buffer.device_pointer,
- const_cast<int *>(&buffer_params.full_x),
- const_cast<int *>(&buffer_params.full_y),
- const_cast<int *>(&buffer_params.width),
- const_cast<int *>(&buffer_params.height),
- const_cast<int *>(&buffer_params.offset),
- const_cast<int *>(&buffer_params.stride),
- const_cast<int *>(&buffer_params.pass_stride),
- const_cast<int *>(&pass.denoised_offset)};
+ DeviceKernelArguments args(&context.render_buffers->buffer.device_pointer,
+ &buffer_params.full_x,
+ &buffer_params.full_y,
+ &buffer_params.width,
+ &buffer_params.height,
+ &buffer_params.offset,
+ &buffer_params.stride,
+ &buffer_params.pass_stride,
+ &pass.denoised_offset);
return denoiser_.queue.enqueue(DEVICE_KERNEL_FILTER_COLOR_PREPROCESS, work_size, args);
}
@@ -797,20 +877,20 @@ bool OptiXDevice::denoise_filter_color_postprocess(DenoiseContext &context,
const int work_size = buffer_params.width * buffer_params.height;
- void *args[] = {&context.render_buffers->buffer.device_pointer,
- const_cast<int *>(&buffer_params.full_x),
- const_cast<int *>(&buffer_params.full_y),
- const_cast<int *>(&buffer_params.width),
- const_cast<int *>(&buffer_params.height),
- const_cast<int *>(&buffer_params.offset),
- const_cast<int *>(&buffer_params.stride),
- const_cast<int *>(&buffer_params.pass_stride),
- const_cast<int *>(&context.num_samples),
- const_cast<int *>(&pass.noisy_offset),
- const_cast<int *>(&pass.denoised_offset),
- const_cast<int *>(&context.pass_sample_count),
- const_cast<int *>(&pass.num_components),
- const_cast<bool *>(&pass.use_compositing)};
+ DeviceKernelArguments args(&context.render_buffers->buffer.device_pointer,
+ &buffer_params.full_x,
+ &buffer_params.full_y,
+ &buffer_params.width,
+ &buffer_params.height,
+ &buffer_params.offset,
+ &buffer_params.stride,
+ &buffer_params.pass_stride,
+ &context.num_samples,
+ &pass.noisy_offset,
+ &pass.denoised_offset,
+ &context.pass_sample_count,
+ &pass.num_components,
+ &pass.use_compositing);
return denoiser_.queue.enqueue(DEVICE_KERNEL_FILTER_COLOR_POSTPROCESS, work_size, args);
}
@@ -834,7 +914,8 @@ bool OptiXDevice::denoise_create_if_needed(DenoiseContext &context)
{
const bool recreate_denoiser = (denoiser_.optix_denoiser == nullptr) ||
(denoiser_.use_pass_albedo != context.use_pass_albedo) ||
- (denoiser_.use_pass_normal != context.use_pass_normal);
+ (denoiser_.use_pass_normal != context.use_pass_normal) ||
+ (denoiser_.use_pass_flow != context.use_pass_flow);
if (!recreate_denoiser) {
return true;
}
@@ -848,8 +929,14 @@ bool OptiXDevice::denoise_create_if_needed(DenoiseContext &context)
OptixDenoiserOptions denoiser_options = {};
denoiser_options.guideAlbedo = context.use_pass_albedo;
denoiser_options.guideNormal = context.use_pass_normal;
+
+ OptixDenoiserModelKind model = OPTIX_DENOISER_MODEL_KIND_HDR;
+ if (context.use_pass_flow) {
+ model = OPTIX_DENOISER_MODEL_KIND_TEMPORAL;
+ }
+
const OptixResult result = optixDenoiserCreate(
- this->context, OPTIX_DENOISER_MODEL_KIND_HDR, &denoiser_options, &denoiser_.optix_denoiser);
+ this->context, model, &denoiser_options, &denoiser_.optix_denoiser);
if (result != OPTIX_SUCCESS) {
set_error("Failed to create OptiX denoiser");
@@ -859,6 +946,7 @@ bool OptiXDevice::denoise_create_if_needed(DenoiseContext &context)
/* OptiX denoiser handle was created with the requested number of input passes. */
denoiser_.use_pass_albedo = context.use_pass_albedo;
denoiser_.use_pass_normal = context.use_pass_normal;
+ denoiser_.use_pass_flow = context.use_pass_flow;
/* OptiX denoiser has been created, but it needs configuration. */
denoiser_.is_configured = false;
@@ -868,41 +956,42 @@ bool OptiXDevice::denoise_create_if_needed(DenoiseContext &context)
bool OptiXDevice::denoise_configure_if_needed(DenoiseContext &context)
{
- if (denoiser_.is_configured && (denoiser_.configured_size.x == context.buffer_params.width &&
- denoiser_.configured_size.y == context.buffer_params.height)) {
+ /* Limit maximum tile size denoiser can be invoked with. */
+ const int2 tile_size = make_int2(min(context.buffer_params.width, 4096),
+ min(context.buffer_params.height, 4096));
+
+ if (denoiser_.is_configured &&
+ (denoiser_.configured_size.x == tile_size.x && denoiser_.configured_size.y == tile_size.y)) {
return true;
}
- const BufferParams &buffer_params = context.buffer_params;
-
- OptixDenoiserSizes sizes = {};
optix_assert(optixDenoiserComputeMemoryResources(
- denoiser_.optix_denoiser, buffer_params.width, buffer_params.height, &sizes));
-
- denoiser_.scratch_size = sizes.withOverlapScratchSizeInBytes;
- denoiser_.scratch_offset = sizes.stateSizeInBytes;
+ denoiser_.optix_denoiser, tile_size.x, tile_size.y, &denoiser_.sizes));
/* Allocate denoiser state if tile size has changed since last setup. */
- denoiser_.state.alloc_to_device(denoiser_.scratch_offset + denoiser_.scratch_size);
+ denoiser_.state.alloc_to_device(denoiser_.sizes.stateSizeInBytes +
+ denoiser_.sizes.withOverlapScratchSizeInBytes);
/* Initialize denoiser state for the current tile size. */
- const OptixResult result = optixDenoiserSetup(denoiser_.optix_denoiser,
- denoiser_.queue.stream(),
- buffer_params.width,
- buffer_params.height,
- denoiser_.state.device_pointer,
- denoiser_.scratch_offset,
- denoiser_.state.device_pointer +
- denoiser_.scratch_offset,
- denoiser_.scratch_size);
+ const OptixResult result = optixDenoiserSetup(
+ denoiser_.optix_denoiser,
+ 0, /* Work around bug in r495 drivers that causes artifacts when denoiser setup is called
+ on a stream that is not the default stream */
+ tile_size.x + denoiser_.sizes.overlapWindowSizeInPixels * 2,
+ tile_size.y + denoiser_.sizes.overlapWindowSizeInPixels * 2,
+ denoiser_.state.device_pointer,
+ denoiser_.sizes.stateSizeInBytes,
+ denoiser_.state.device_pointer + denoiser_.sizes.stateSizeInBytes,
+ denoiser_.sizes.withOverlapScratchSizeInBytes);
if (result != OPTIX_SUCCESS) {
set_error("Failed to set up OptiX denoiser");
return false;
}
+ cuda_assert(cuCtxSynchronize());
+
denoiser_.is_configured = true;
- denoiser_.configured_size.x = buffer_params.width;
- denoiser_.configured_size.y = buffer_params.height;
+ denoiser_.configured_size = tile_size;
return true;
}
@@ -917,8 +1006,10 @@ bool OptiXDevice::denoise_run(DenoiseContext &context, const DenoisePass &pass)
OptixImage2D color_layer = {0};
OptixImage2D albedo_layer = {0};
OptixImage2D normal_layer = {0};
+ OptixImage2D flow_layer = {0};
OptixImage2D output_layer = {0};
+ OptixImage2D prev_output_layer = {0};
/* Color pass. */
{
@@ -934,7 +1025,18 @@ bool OptiXDevice::denoise_run(DenoiseContext &context, const DenoisePass &pass)
color_layer.format = OPTIX_PIXEL_FORMAT_FLOAT3;
}
- device_vector<float> fake_albedo(this, "fake_albedo", MEM_READ_WRITE);
+ /* Previous output. */
+ if (context.prev_output.offset != PASS_UNUSED) {
+ const int64_t pass_stride_in_bytes = context.prev_output.pass_stride * sizeof(float);
+
+ prev_output_layer.data = context.prev_output.device_pointer +
+ context.prev_output.offset * sizeof(float);
+ prev_output_layer.width = width;
+ prev_output_layer.height = height;
+ prev_output_layer.rowStrideInBytes = pass_stride_in_bytes * context.prev_output.stride;
+ prev_output_layer.pixelStrideInBytes = pass_stride_in_bytes;
+ prev_output_layer.format = OPTIX_PIXEL_FORMAT_FLOAT3;
+ }
/* Optional albedo and color passes. */
if (context.num_input_passes > 1) {
@@ -959,33 +1061,47 @@ bool OptiXDevice::denoise_run(DenoiseContext &context, const DenoisePass &pass)
normal_layer.pixelStrideInBytes = pixel_stride_in_bytes;
normal_layer.format = OPTIX_PIXEL_FORMAT_FLOAT3;
}
+
+ if (context.use_pass_flow) {
+ flow_layer.data = d_guiding_buffer + context.guiding_params.pass_flow * sizeof(float);
+ flow_layer.width = width;
+ flow_layer.height = height;
+ flow_layer.rowStrideInBytes = row_stride_in_bytes;
+ flow_layer.pixelStrideInBytes = pixel_stride_in_bytes;
+ flow_layer.format = OPTIX_PIXEL_FORMAT_FLOAT2;
+ }
}
/* Denoise in-place of the noisy input in the render buffers. */
output_layer = color_layer;
- /* Finally run denoising. */
- OptixDenoiserParams params = {}; /* All parameters are disabled/zero. */
+ OptixDenoiserGuideLayer guide_layers = {};
+ guide_layers.albedo = albedo_layer;
+ guide_layers.normal = normal_layer;
+ guide_layers.flow = flow_layer;
+
OptixDenoiserLayer image_layers = {};
image_layers.input = color_layer;
+ image_layers.previousOutput = prev_output_layer;
image_layers.output = output_layer;
- OptixDenoiserGuideLayer guide_layers = {};
- guide_layers.albedo = albedo_layer;
- guide_layers.normal = normal_layer;
+ /* Finally run denoising. */
+ OptixDenoiserParams params = {}; /* All parameters are disabled/zero. */
- optix_assert(optixDenoiserInvoke(denoiser_.optix_denoiser,
- denoiser_.queue.stream(),
- &params,
- denoiser_.state.device_pointer,
- denoiser_.scratch_offset,
- &guide_layers,
- &image_layers,
- 1,
- 0,
- 0,
- denoiser_.state.device_pointer + denoiser_.scratch_offset,
- denoiser_.scratch_size));
+ optix_assert(optixUtilDenoiserInvokeTiled(denoiser_.optix_denoiser,
+ denoiser_.queue.stream(),
+ &params,
+ denoiser_.state.device_pointer,
+ denoiser_.sizes.stateSizeInBytes,
+ &guide_layers,
+ &image_layers,
+ 1,
+ denoiser_.state.device_pointer +
+ denoiser_.sizes.stateSizeInBytes,
+ denoiser_.sizes.withOverlapScratchSizeInBytes,
+ denoiser_.sizes.overlapWindowSizeInPixels,
+ denoiser_.configured_size.x,
+ denoiser_.configured_size.y));
return true;
}
@@ -995,6 +1111,13 @@ bool OptiXDevice::build_optix_bvh(BVHOptiX *bvh,
const OptixBuildInput &build_input,
uint16_t num_motion_steps)
{
+ /* Allocate and build acceleration structures only one at a time, to prevent parallel builds
+ * from running out of memory (since both original and compacted acceleration structure memory
+ * may be allocated at the same time for the duration of this function). The builds would
+ * otherwise happen on the same CUDA stream anyway. */
+ static thread_mutex mutex;
+ thread_scoped_lock lock(mutex);
+
const CUDAContextScope scope(this);
const bool use_fast_trace_bvh = (bvh->params.bvh_type == BVH_TYPE_STATIC);
@@ -1020,14 +1143,15 @@ bool OptiXDevice::build_optix_bvh(BVHOptiX *bvh,
optix_assert(optixAccelComputeMemoryUsage(context, &options, &build_input, 1, &sizes));
/* Allocate required output buffers. */
- device_only_memory<char> temp_mem(this, "optix temp as build mem");
+ device_only_memory<char> temp_mem(this, "optix temp as build mem", true);
temp_mem.alloc_to_device(align_up(sizes.tempSizeInBytes, 8) + 8);
if (!temp_mem.device_pointer) {
/* Make sure temporary memory allocation succeeded. */
return false;
}
- device_only_memory<char> &out_data = bvh->as_data;
+ /* Acceleration structure memory has to be allocated on the device (not allowed on the host). */
+ device_only_memory<char> &out_data = *bvh->as_data;
if (operation == OPTIX_BUILD_OPERATION_BUILD) {
assert(out_data.device == this);
out_data.alloc_to_device(sizes.outputSizeInBytes);
@@ -1075,12 +1199,13 @@ bool OptiXDevice::build_optix_bvh(BVHOptiX *bvh,
/* There is no point compacting if the size does not change. */
if (compacted_size < sizes.outputSizeInBytes) {
- device_only_memory<char> compacted_data(this, "optix compacted as");
+ device_only_memory<char> compacted_data(this, "optix compacted as", false);
compacted_data.alloc_to_device(compacted_size);
- if (!compacted_data.device_pointer)
+ if (!compacted_data.device_pointer) {
/* Do not compact if memory allocation for compacted acceleration structure fails.
* Can just use the uncompacted one then, so succeed here regardless. */
return !have_error();
+ }
optix_assert(optixAccelCompact(
context, NULL, out_handle, compacted_data.device_pointer, compacted_size, &out_handle));
@@ -1091,6 +1216,8 @@ bool OptiXDevice::build_optix_bvh(BVHOptiX *bvh,
std::swap(out_data.device_size, compacted_data.device_size);
std::swap(out_data.device_pointer, compacted_data.device_pointer);
+ /* Original acceleration structure memory is freed when 'compacted_data' goes out of scope.
+ */
}
}
@@ -1118,7 +1245,7 @@ void OptiXDevice::build_bvh(BVH *bvh, Progress &progress, bool refit)
operation = OPTIX_BUILD_OPERATION_UPDATE;
}
else {
- bvh_optix->as_data.free();
+ bvh_optix->as_data->free();
bvh_optix->traversable_handle = 0;
}
@@ -1173,20 +1300,27 @@ void OptiXDevice::build_bvh(BVH *bvh, Progress &progress, bool refit)
int ka = max(k0 - 1, curve.first_key);
int kb = min(k1 + 1, curve.first_key + curve.num_keys - 1);
+ index_data[i] = i * 4;
+ float4 *const v = vertex_data.data() + step * num_vertices + index_data[i];
+
+# if OPTIX_ABI_VERSION >= 55
+ v[0] = make_float4(keys[ka].x, keys[ka].y, keys[ka].z, curve_radius[ka]);
+ v[1] = make_float4(keys[k0].x, keys[k0].y, keys[k0].z, curve_radius[k0]);
+ v[2] = make_float4(keys[k1].x, keys[k1].y, keys[k1].z, curve_radius[k1]);
+ v[3] = make_float4(keys[kb].x, keys[kb].y, keys[kb].z, curve_radius[kb]);
+# else
const float4 px = make_float4(keys[ka].x, keys[k0].x, keys[k1].x, keys[kb].x);
const float4 py = make_float4(keys[ka].y, keys[k0].y, keys[k1].y, keys[kb].y);
const float4 pz = make_float4(keys[ka].z, keys[k0].z, keys[k1].z, keys[kb].z);
const float4 pw = make_float4(
curve_radius[ka], curve_radius[k0], curve_radius[k1], curve_radius[kb]);
- /* Convert Catmull-Rom data to Bezier spline. */
+ /* Convert Catmull-Rom data to B-spline. */
static const float4 cr2bsp0 = make_float4(+7, -4, +5, -2) / 6.f;
static const float4 cr2bsp1 = make_float4(-2, 11, -4, +1) / 6.f;
static const float4 cr2bsp2 = make_float4(+1, -4, 11, -2) / 6.f;
static const float4 cr2bsp3 = make_float4(-2, +5, -4, +7) / 6.f;
- index_data[i] = i * 4;
- float4 *const v = vertex_data.data() + step * num_vertices + index_data[i];
v[0] = make_float4(
dot(cr2bsp0, px), dot(cr2bsp0, py), dot(cr2bsp0, pz), dot(cr2bsp0, pw));
v[1] = make_float4(
@@ -1195,6 +1329,7 @@ void OptiXDevice::build_bvh(BVH *bvh, Progress &progress, bool refit)
dot(cr2bsp2, px), dot(cr2bsp2, py), dot(cr2bsp2, pz), dot(cr2bsp2, pw));
v[3] = make_float4(
dot(cr2bsp3, px), dot(cr2bsp3, py), dot(cr2bsp3, pz), dot(cr2bsp3, pw));
+# endif
}
else {
BoundBox bounds = BoundBox::empty;
@@ -1236,7 +1371,11 @@ void OptiXDevice::build_bvh(BVH *bvh, Progress &progress, bool refit)
OptixBuildInput build_input = {};
if (hair->curve_shape == CURVE_THICK) {
build_input.type = OPTIX_BUILD_INPUT_TYPE_CURVES;
+# if OPTIX_ABI_VERSION >= 55
+ build_input.curveArray.curveType = OPTIX_PRIMITIVE_TYPE_ROUND_CATMULLROM;
+# else
build_input.curveArray.curveType = OPTIX_PRIMITIVE_TYPE_ROUND_CUBIC_BSPLINE;
+# endif
build_input.curveArray.numPrimitives = num_segments;
build_input.curveArray.vertexBuffers = (CUdeviceptr *)vertex_ptrs.data();
build_input.curveArray.numVertices = num_vertices;
@@ -1246,11 +1385,11 @@ void OptiXDevice::build_bvh(BVH *bvh, Progress &progress, bool refit)
build_input.curveArray.indexBuffer = (CUdeviceptr)index_data.device_pointer;
build_input.curveArray.indexStrideInBytes = sizeof(int);
build_input.curveArray.flag = build_flags;
- build_input.curveArray.primitiveIndexOffset = hair->optix_prim_offset;
+ build_input.curveArray.primitiveIndexOffset = hair->curve_segment_offset;
}
else {
/* Disable visibility test any-hit program, since it is already checked during
- * intersection. Those trace calls that require anyhit can force it with a ray flag. */
+ * intersection. Those trace calls that require any-hit can force it with a ray flag. */
build_flags |= OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT;
build_input.type = OPTIX_BUILD_INPUT_TYPE_CUSTOM_PRIMITIVES;
@@ -1259,7 +1398,7 @@ void OptiXDevice::build_bvh(BVH *bvh, Progress &progress, bool refit)
build_input.customPrimitiveArray.strideInBytes = sizeof(OptixAabb);
build_input.customPrimitiveArray.flags = &build_flags;
build_input.customPrimitiveArray.numSbtRecords = 1;
- build_input.customPrimitiveArray.primitiveIndexOffset = hair->optix_prim_offset;
+ build_input.customPrimitiveArray.primitiveIndexOffset = hair->curve_segment_offset;
}
if (!build_optix_bvh(bvh_optix, operation, build_input, num_motion_steps)) {
@@ -1328,7 +1467,87 @@ void OptiXDevice::build_bvh(BVH *bvh, Progress &progress, bool refit)
* buffers for that purpose. OptiX does not allow this to be zero though, so just pass in
* one and rely on that having the same meaning in this case. */
build_input.triangleArray.numSbtRecords = 1;
- build_input.triangleArray.primitiveIndexOffset = mesh->optix_prim_offset;
+ build_input.triangleArray.primitiveIndexOffset = mesh->prim_offset;
+
+ if (!build_optix_bvh(bvh_optix, operation, build_input, num_motion_steps)) {
+ progress.set_error("Failed to build OptiX acceleration structure");
+ }
+ }
+ else if (geom->geometry_type == Geometry::POINTCLOUD) {
+ /* Build BLAS for points primitives. */
+ PointCloud *const pointcloud = static_cast<PointCloud *const>(geom);
+ const size_t num_points = pointcloud->num_points();
+ if (num_points == 0) {
+ return;
+ }
+
+ size_t num_motion_steps = 1;
+ Attribute *motion_points = pointcloud->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ if (motion_blur && pointcloud->get_use_motion_blur() && motion_points) {
+ num_motion_steps = pointcloud->get_motion_steps();
+ }
+
+ device_vector<OptixAabb> aabb_data(this, "optix temp aabb data", MEM_READ_ONLY);
+ aabb_data.alloc(num_points * num_motion_steps);
+
+ /* Get AABBs for each motion step. */
+ for (size_t step = 0; step < num_motion_steps; ++step) {
+ /* The center step for motion vertices is not stored in the attribute. */
+ const float3 *points = pointcloud->get_points().data();
+ const float *radius = pointcloud->get_radius().data();
+ size_t center_step = (num_motion_steps - 1) / 2;
+ if (step != center_step) {
+ size_t attr_offset = (step > center_step) ? step - 1 : step;
+ /* Technically this is a float4 array, but sizeof(float3) == sizeof(float4). */
+ points = motion_points->data_float3() + attr_offset * num_points;
+ }
+
+ for (size_t i = 0; i < num_points; ++i) {
+ const PointCloud::Point point = pointcloud->get_point(i);
+ BoundBox bounds = BoundBox::empty;
+ point.bounds_grow(points, radius, bounds);
+
+ const size_t index = step * num_points + i;
+ aabb_data[index].minX = bounds.min.x;
+ aabb_data[index].minY = bounds.min.y;
+ aabb_data[index].minZ = bounds.min.z;
+ aabb_data[index].maxX = bounds.max.x;
+ aabb_data[index].maxY = bounds.max.y;
+ aabb_data[index].maxZ = bounds.max.z;
+ }
+ }
+
+ /* Upload AABB data to GPU. */
+ aabb_data.copy_to_device();
+
+ vector<device_ptr> aabb_ptrs;
+ aabb_ptrs.reserve(num_motion_steps);
+ for (size_t step = 0; step < num_motion_steps; ++step) {
+ aabb_ptrs.push_back(aabb_data.device_pointer + step * num_points * sizeof(OptixAabb));
+ }
+
+ /* Disable visibility test any-hit program, since it is already checked during
+ * intersection. Those trace calls that require anyhit can force it with a ray flag.
+ * For those, force a single any-hit call, so shadow record-all behavior works correctly. */
+ unsigned int build_flags = OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT |
+ OPTIX_GEOMETRY_FLAG_REQUIRE_SINGLE_ANYHIT_CALL;
+ OptixBuildInput build_input = {};
+ build_input.type = OPTIX_BUILD_INPUT_TYPE_CUSTOM_PRIMITIVES;
+# if OPTIX_ABI_VERSION < 23
+ build_input.aabbArray.aabbBuffers = (CUdeviceptr *)aabb_ptrs.data();
+ build_input.aabbArray.numPrimitives = num_points;
+ build_input.aabbArray.strideInBytes = sizeof(OptixAabb);
+ build_input.aabbArray.flags = &build_flags;
+ build_input.aabbArray.numSbtRecords = 1;
+ build_input.aabbArray.primitiveIndexOffset = pointcloud->prim_offset;
+# else
+ build_input.customPrimitiveArray.aabbBuffers = (CUdeviceptr *)aabb_ptrs.data();
+ build_input.customPrimitiveArray.numPrimitives = num_points;
+ build_input.customPrimitiveArray.strideInBytes = sizeof(OptixAabb);
+ build_input.customPrimitiveArray.flags = &build_flags;
+ build_input.customPrimitiveArray.numSbtRecords = 1;
+ build_input.customPrimitiveArray.primitiveIndexOffset = pointcloud->prim_offset;
+# endif
if (!build_optix_bvh(bvh_optix, operation, build_input, num_motion_steps)) {
progress.set_error("Failed to build OptiX acceleration structure");
@@ -1339,9 +1558,9 @@ void OptiXDevice::build_bvh(BVH *bvh, Progress &progress, bool refit)
unsigned int num_instances = 0;
unsigned int max_num_instances = 0xFFFFFFFF;
- bvh_optix->as_data.free();
+ bvh_optix->as_data->free();
bvh_optix->traversable_handle = 0;
- bvh_optix->motion_transform_data.free();
+ bvh_optix->motion_transform_data->free();
optixDeviceContextGetProperty(context,
OPTIX_DEVICE_PROPERTY_LIMIT_MAX_INSTANCE_ID,
@@ -1374,8 +1593,8 @@ void OptiXDevice::build_bvh(BVH *bvh, Progress &progress, bool refit)
}
}
- assert(bvh_optix->motion_transform_data.device == this);
- bvh_optix->motion_transform_data.alloc_to_device(total_motion_transform_size);
+ assert(bvh_optix->motion_transform_data->device == this);
+ bvh_optix->motion_transform_data->alloc_to_device(total_motion_transform_size);
}
for (Object *ob : bvh->objects) {
@@ -1395,8 +1614,8 @@ void OptiXDevice::build_bvh(BVH *bvh, Progress &progress, bool refit)
instance.transform[5] = 1.0f;
instance.transform[10] = 1.0f;
- /* Set user instance ID to object index (but leave low bit blank). */
- instance.instanceId = ob->get_device_index() << 1;
+ /* Set user instance ID to object index. */
+ instance.instanceId = ob->get_device_index();
/* Add some of the object visibility bits to the mask.
* __prim_visibility contains the combined visibility bits of all instances, so is not
@@ -1417,9 +1636,22 @@ void OptiXDevice::build_bvh(BVH *bvh, Progress &progress, bool refit)
instance.sbtOffset = PG_HITD_MOTION - PG_HITD;
}
}
- else {
+ else if (ob->get_geometry()->geometry_type == Geometry::POINTCLOUD) {
+ /* Use the hit group that has an intersection program for point clouds. */
+ instance.sbtOffset = PG_HITD_POINTCLOUD - PG_HITD;
+
+ /* Also skip point clouds in local trace calls. */
+ instance.visibilityMask |= 4;
+ }
+
+# if OPTIX_ABI_VERSION < 55
+ /* Cannot disable any-hit program for thick curves, since it needs to filter out end-caps. */
+ else
+# endif
+ {
/* Can disable __anyhit__kernel_optix_visibility_test by default (except for thick curves,
- * since it needs to filter out endcaps there).
+ * since it needs to filter out end-caps there).
+
* It is enabled where necessary (visibility mask exceeds 8 bits or the other any-hit
* programs like __anyhit__kernel_optix_shadow_all_hit) via OPTIX_RAY_FLAG_ENFORCE_ANYHIT.
*/
@@ -1436,7 +1668,7 @@ void OptiXDevice::build_bvh(BVH *bvh, Progress &progress, bool refit)
motion_transform_offset = align_up(motion_transform_offset,
OPTIX_TRANSFORM_BYTE_ALIGNMENT);
- CUdeviceptr motion_transform_gpu = bvh_optix->motion_transform_data.device_pointer +
+ CUdeviceptr motion_transform_gpu = bvh_optix->motion_transform_data->device_pointer +
motion_transform_offset;
motion_transform_offset += motion_transform_size;
@@ -1489,9 +1721,6 @@ void OptiXDevice::build_bvh(BVH *bvh, Progress &progress, bool refit)
cuMemcpyHtoD(motion_transform_gpu, &motion_transform, motion_transform_size);
delete[] reinterpret_cast<uint8_t *>(&motion_transform);
- /* Disable instance transform if object uses motion transform already. */
- instance.flags |= OPTIX_INSTANCE_FLAG_DISABLE_TRANSFORM;
-
/* Get traversable handle to motion transform. */
optixConvertPointerToTraversableHandle(context,
motion_transform_gpu,
@@ -1505,13 +1734,6 @@ void OptiXDevice::build_bvh(BVH *bvh, Progress &progress, bool refit)
/* Set transform matrix. */
memcpy(instance.transform, &ob->get_tfm(), sizeof(instance.transform));
}
- else {
- /* Disable instance transform if geometry already has it applied to vertex data. */
- instance.flags |= OPTIX_INSTANCE_FLAG_DISABLE_TRANSFORM;
- /* Non-instanced objects read ID from 'prim_object', so distinguish
- * them from instanced objects with the low bit set. */
- instance.instanceId |= 1;
- }
}
}
@@ -1573,7 +1795,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 3695ac6afc2..a1865527c2d 100644
--- a/intern/cycles/device/optix/device_impl.h
+++ b/intern/cycles/device/optix/device_impl.h
@@ -22,7 +22,8 @@
# 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"
+# include "util/unique_ptr.h"
CCL_NAMESPACE_BEGIN
@@ -43,18 +44,19 @@ enum {
PG_HITV, /* __VOLUME__ hit group. */
PG_HITD_MOTION,
PG_HITS_MOTION,
+ PG_HITD_POINTCLOUD,
+ PG_HITS_POINTCLOUD,
PG_CALL_SVM_AO,
PG_CALL_SVM_BEVEL,
- PG_CALL_AO_PASS,
NUM_PROGRAM_GROUPS
};
static const int MISS_PROGRAM_GROUP_OFFSET = PG_MISS;
static const int NUM_MIS_PROGRAM_GROUPS = 1;
static const int HIT_PROGAM_GROUP_OFFSET = PG_HITD;
-static const int NUM_HIT_PROGRAM_GROUPS = 6;
+static const int NUM_HIT_PROGRAM_GROUPS = 8;
static const int CALLABLE_PROGRAM_GROUPS_BASE = PG_CALL_SVM_AO;
-static const int NUM_CALLABLE_PROGRAM_GROUPS = 3;
+static const int NUM_CALLABLE_PROGRAM_GROUPS = 2;
/* List of OptiX pipelines. */
enum { PIP_SHADE_RAYTRACE, PIP_INTERSECT, NUM_PIPELINES };
@@ -77,13 +79,12 @@ class OptiXDevice : public CUDADevice {
device_only_memory<KernelParamsOptiX> launch_params;
OptixTraversableHandle tlas_handle = 0;
- vector<device_only_memory<char>> delayed_free_bvh_memory;
+ vector<unique_ptr<device_only_memory<char>>> delayed_free_bvh_memory;
thread_mutex delayed_free_bvh_mutex;
class Denoiser {
public:
explicit Denoiser(OptiXDevice *device);
- ~Denoiser();
OptiXDevice *device;
OptiXDeviceQueue queue;
@@ -99,11 +100,11 @@ class OptiXDevice : public CUDADevice {
/* OptiX denoiser state and scratch buffers, stored in a single memory buffer.
* The memory layout goes as following: [denoiser state][scratch buffer]. */
device_only_memory<unsigned char> state;
- size_t scratch_offset = 0;
- size_t scratch_size = 0;
+ OptixDenoiserSizes sizes = {};
bool use_pass_albedo = false;
bool use_pass_normal = false;
+ bool use_pass_flow = false;
};
Denoiser denoiser_;
diff --git a/intern/cycles/device/optix/queue.cpp b/intern/cycles/device/optix/queue.cpp
index 458ed70baa8..1a437878b5f 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__
@@ -47,7 +47,9 @@ static bool is_optix_specific_kernel(DeviceKernel kernel)
kernel == DEVICE_KERNEL_INTEGRATOR_INTERSECT_VOLUME_STACK);
}
-bool OptiXDeviceQueue::enqueue(DeviceKernel kernel, const int work_size, void *args[])
+bool OptiXDeviceQueue::enqueue(DeviceKernel kernel,
+ const int work_size,
+ DeviceKernelArguments const &args)
{
if (!is_optix_specific_kernel(kernel)) {
return CUDADeviceQueue::enqueue(kernel, work_size, args);
@@ -69,15 +71,16 @@ bool OptiXDeviceQueue::enqueue(DeviceKernel kernel, const int work_size, void *a
cuda_device_assert(
cuda_device_,
cuMemcpyHtoDAsync(launch_params_ptr + offsetof(KernelParamsOptiX, path_index_array),
- args[0], // &d_path_index
+ args.values[0], // &d_path_index
sizeof(device_ptr),
cuda_stream_));
- if (kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE) {
+ if (kernel == DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST ||
+ kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE) {
cuda_device_assert(
cuda_device_,
cuMemcpyHtoDAsync(launch_params_ptr + offsetof(KernelParamsOptiX, render_buffer),
- args[1], // &d_render_buffer
+ args.values[1], // &d_render_buffer
sizeof(device_ptr),
cuda_stream_));
}
diff --git a/intern/cycles/device/optix/queue.h b/intern/cycles/device/optix/queue.h
index 0de422ccc71..5f0e09dff2c 100644
--- a/intern/cycles/device/optix/queue.h
+++ b/intern/cycles/device/optix/queue.h
@@ -31,7 +31,9 @@ class OptiXDeviceQueue : public CUDADeviceQueue {
virtual void init_execution() override;
- virtual bool enqueue(DeviceKernel kernel, const int work_size, void *args[]) override;
+ virtual bool enqueue(DeviceKernel kernel,
+ const int work_size,
+ DeviceKernelArguments const &args) override;
};
CCL_NAMESPACE_END
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..926b7cba78a
--- /dev/null
+++ b/intern/cycles/device/queue.h
@@ -0,0 +1,186 @@
+/*
+ * 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/debug.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;
+
+/* Container for device kernel arguments with type correctness ensured by API. */
+struct DeviceKernelArguments {
+
+ enum Type {
+ POINTER,
+ INT32,
+ FLOAT32,
+ BOOLEAN,
+ KERNEL_FILM_CONVERT,
+ };
+
+ static const int MAX_ARGS = 18;
+ Type types[MAX_ARGS];
+ void *values[MAX_ARGS];
+ size_t sizes[MAX_ARGS];
+ size_t count = 0;
+
+ DeviceKernelArguments()
+ {
+ }
+
+ template<class T> DeviceKernelArguments(const T *arg)
+ {
+ add(arg);
+ }
+
+ template<class T, class... Args> DeviceKernelArguments(const T *first, Args... args)
+ {
+ add(first);
+ add(args...);
+ }
+
+ void add(const KernelFilmConvert *value)
+ {
+ add(KERNEL_FILM_CONVERT, value, sizeof(KernelFilmConvert));
+ }
+ void add(const device_ptr *value)
+ {
+ add(POINTER, value, sizeof(device_ptr));
+ }
+ void add(const int32_t *value)
+ {
+ add(INT32, value, sizeof(int32_t));
+ }
+ void add(const float *value)
+ {
+ add(FLOAT32, value, sizeof(float));
+ }
+ void add(const bool *value)
+ {
+ add(BOOLEAN, value, 4);
+ }
+ void add(const Type type, const void *value, size_t size)
+ {
+ assert(count < MAX_ARGS);
+
+ types[count] = type;
+ values[count] = (void *)value;
+ sizes[count] = size;
+ count++;
+ }
+ template<typename T, typename... Args> void add(const T *first, Args... args)
+ {
+ add(first);
+ add(args...);
+ }
+};
+
+/* 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,
+ DeviceKernelArguments const &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/doc/license/readme.txt b/intern/cycles/doc/license/readme.txt
index cc5476e3511..f610d800ebc 100644
--- a/intern/cycles/doc/license/readme.txt
+++ b/intern/cycles/doc/license/readme.txt
@@ -3,7 +3,7 @@ This program uses code from various sources, the default license is Apache 2.0
for all code, with the following exceptions.
Modified BSD License
-* Code adapated from Open Shading Language
+* Code adapted from Open Shading Language
* Sobol direction vectors
* Matrix inversion code from OpenEXR
* MD5 Hash code
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..8b505c0eb9e 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
@@ -31,7 +31,7 @@ struct Node;
struct NodeType;
struct Transform;
-/* Note: in the following macros we use "type const &" instead of "const type &"
+/* NOTE: in the following macros we use "type const &" instead of "const type &"
* to avoid issues when pasting a pointer type. */
#define NODE_SOCKET_API_BASE_METHODS(type_, name, string_name) \
const SocketType *get_##name##_socket() const \
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 bfabd35d7c3..dedde513409 100644
--- a/intern/cycles/integrator/CMakeLists.txt
+++ b/intern/cycles/integrator/CMakeLists.txt
@@ -27,6 +27,8 @@ set(SRC
pass_accessor.cpp
pass_accessor_cpu.cpp
pass_accessor_gpu.cpp
+ path_trace_display.cpp
+ path_trace_tile.cpp
path_trace_work.cpp
path_trace_work_cpu.cpp
path_trace_work_gpu.cpp
@@ -47,6 +49,8 @@ set(SRC_HEADERS
pass_accessor.h
pass_accessor_cpu.h
pass_accessor_gpu.h
+ path_trace_display.h
+ path_trace_tile.h
path_trace_work.h
path_trace_work_cpu.h
path_trace_work_gpu.h
@@ -57,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..2a5f99f358b 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
@@ -29,23 +29,14 @@ unique_ptr<Denoiser> Denoiser::create(Device *path_trace_device, const DenoisePa
{
DCHECK(params.use);
- switch (params.type) {
- case DENOISER_OPTIX:
- return make_unique<OptiXDenoiser>(path_trace_device, params);
-
- case DENOISER_OPENIMAGEDENOISE:
- return make_unique<OIDNDenoiser>(path_trace_device, params);
-
- case DENOISER_NUM:
- case DENOISER_NONE:
- case DENOISER_ALL:
- /* pass */
- break;
+ if (params.type == DENOISER_OPTIX && Device::available_devices(DEVICE_MASK_OPTIX).size()) {
+ return make_unique<OptiXDenoiser>(path_trace_device, params);
}
- LOG(FATAL) << "Unhandled denoiser type " << params.type << ", should never happen.";
-
- return nullptr;
+ /* Always fallback to OIDN. */
+ DenoiseParams oidn_params = params;
+ oidn_params.type = DENOISER_OPENIMAGEDENOISE;
+ return make_unique<OIDNDenoiser>(path_trace_device, oidn_params);
}
Denoiser::Denoiser(Device *path_trace_device, const DenoiseParams &params)
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 7fc2b2b1892..a08aec513fc 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"
@@ -47,9 +47,6 @@ static bool oidn_progress_monitor_function(void *user_ptr, double /*n*/)
OIDNDenoiser *oidn_denoiser = reinterpret_cast<OIDNDenoiser *>(user_ptr);
return !oidn_denoiser->is_cancelled();
}
-#endif
-
-#ifdef WITH_OPENIMAGEDENOISE
class OIDNPass {
public:
@@ -169,6 +166,7 @@ class OIDNDenoiseContext {
OIDNPass oidn_color_access_pass = read_input_pass(oidn_color_pass, oidn_output_pass);
oidn::DeviceRef oidn_device = oidn::newDevice();
+ oidn_device.set("setAffinity", false);
oidn_device.commit();
/* Create a filter for denoising a beauty (color) image using prefiltered auxiliary images too.
@@ -289,7 +287,13 @@ class OIDNDenoiseContext {
* pixels. */
const PassAccessorCPU pass_accessor(pass_access_info, 1.0f, num_samples_);
- pass_accessor.get_render_tile_pixels(render_buffers_, buffer_params_, destination);
+ BufferParams buffer_params = buffer_params_;
+ buffer_params.window_x = 0;
+ buffer_params.window_y = 0;
+ buffer_params.window_width = buffer_params.width;
+ buffer_params.window_height = buffer_params.height;
+
+ pass_accessor.get_render_tile_pixels(render_buffers_, buffer_params, destination);
}
/* Read pass pixels using PassAccessor into a temporary buffer which is owned by the pass.. */
@@ -540,7 +544,6 @@ class OIDNDenoiseContext {
* the fake values and denoising of passes which do need albedo can no longer happen. */
bool albedo_replaced_with_fake_ = false;
};
-#endif
static unique_ptr<DeviceQueue> create_device_queue(const RenderBuffers *render_buffers)
{
@@ -575,18 +578,20 @@ static void copy_render_buffers_to_device(unique_ptr<DeviceQueue> &queue,
}
}
+#endif
+
bool OIDNDenoiser::denoise_buffer(const BufferParams &buffer_params,
RenderBuffers *render_buffers,
const int num_samples,
bool allow_inplace_modification)
{
+#ifdef WITH_OPENIMAGEDENOISE
thread_scoped_lock lock(mutex_);
/* Make sure the host-side data is available for denoising. */
unique_ptr<DeviceQueue> queue = create_device_queue(render_buffers);
copy_render_buffers_from_device(queue, render_buffers);
-#ifdef WITH_OPENIMAGEDENOISE
OIDNDenoiseContext context(
this, params_, buffer_params, render_buffers, num_samples, allow_inplace_modification);
@@ -613,6 +618,11 @@ bool OIDNDenoiser::denoise_buffer(const BufferParams &buffer_params,
* copies data from the device it doesn't overwrite the denoiser buffers. */
copy_render_buffers_to_device(queue, render_buffers);
}
+#else
+ (void)buffer_params;
+ (void)render_buffers;
+ (void)num_samples;
+ (void)allow_inplace_modification;
#endif
/* This code is not supposed to run when compiled without OIDN support, so can assume if we made
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 87c048b1fa5..9fa5aab9ea9 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
@@ -96,9 +96,12 @@ static void pad_pixels(const BufferParams &buffer_params,
return;
}
- const size_t size = buffer_params.width * buffer_params.height;
+ const size_t size = static_cast<size_t>(buffer_params.width) * buffer_params.height;
if (destination.pixels) {
- float *pixel = destination.pixels;
+ const size_t pixel_stride = destination.pixel_stride ? destination.pixel_stride :
+ destination.num_components;
+
+ float *pixel = destination.pixels + pixel_stride * destination.offset;
for (size_t i = 0; i < size; i++, pixel += dest_num_components) {
if (dest_num_components >= 3 && src_num_components == 1) {
@@ -112,8 +115,8 @@ static void pad_pixels(const BufferParams &buffer_params,
}
if (destination.pixels_half_rgba) {
- const half one = float_to_half(1.0f);
- half4 *pixel = destination.pixels_half_rgba;
+ const half one = float_to_half_display(1.0f);
+ half4 *pixel = destination.pixels_half_rgba + destination.offset;
for (size_t i = 0; i < size; i++, pixel++) {
if (dest_num_components >= 3 && src_num_components == 1) {
@@ -135,13 +138,10 @@ bool PassAccessor::get_render_tile_pixels(const RenderBuffers *render_buffers,
return false;
}
- if (pass_access_info_.offset == PASS_UNUSED) {
- return false;
- }
-
const PassType type = pass_access_info_.type;
const PassMode mode = pass_access_info_.mode;
const PassInfo pass_info = Pass::get_info(type, pass_access_info_.include_albedo);
+ int num_written_components = pass_info.num_components;
if (pass_info.num_components == 1) {
/* Single channel passes. */
@@ -149,9 +149,6 @@ bool PassAccessor::get_render_tile_pixels(const RenderBuffers *render_buffers,
/* Denoised passes store their final pixels, no need in special calculation. */
get_pass_float(render_buffers, buffer_params, destination);
}
- else if (type == PASS_RENDER_TIME) {
- /* TODO(sergey): Needs implementation. */
- }
else if (type == PASS_DEPTH) {
get_pass_depth(render_buffers, buffer_params, destination);
}
@@ -192,8 +189,10 @@ bool PassAccessor::get_render_tile_pixels(const RenderBuffers *render_buffers,
else if ((pass_info.divide_type != PASS_NONE || pass_info.direct_type != PASS_NONE ||
pass_info.indirect_type != PASS_NONE) &&
mode != PassMode::DENOISED) {
- /* RGB lighting passes that need to divide out color and/or sum direct and indirect. */
+ /* RGB lighting passes that need to divide out color and/or sum direct and indirect.
+ * These can also optionally write alpha like the combined pass. */
get_pass_light_path(render_buffers, buffer_params, destination);
+ num_written_components = 4;
}
else {
/* Passes that need no special computation, or denoised passes that already
@@ -219,7 +218,7 @@ bool PassAccessor::get_render_tile_pixels(const RenderBuffers *render_buffers,
}
}
- pad_pixels(buffer_params, destination, pass_info.num_components);
+ pad_pixels(buffer_params, destination, num_written_components);
return true;
}
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 3c6691f6d43..77ca332d142 100644
--- a/intern/cycles/integrator/pass_accessor_cpu.cpp
+++ b/intern/cycles/integrator/pass_accessor_cpu.cpp
@@ -14,17 +14,20 @@
* limitations under the License.
*/
+#include "device/device.h"
+
#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
@@ -33,117 +36,56 @@ CCL_NAMESPACE_BEGIN
* Kernel processing.
*/
-template<typename Processor>
-inline void PassAccessorCPU::run_get_pass_kernel_processor(const RenderBuffers *render_buffers,
- const BufferParams &buffer_params,
- const Destination &destination,
- const Processor &processor) const
-{
- KernelFilmConvert kfilm_convert;
- init_kernel_film_convert(&kfilm_convert, buffer_params, destination);
-
- if (destination.pixels) {
- /* NOTE: No overlays are applied since they are not used for final renders.
- * Can be supported via some sort of specialization to avoid code duplication. */
-
- run_get_pass_kernel_processor_float(
- &kfilm_convert, render_buffers, buffer_params, destination, processor);
- }
-
- if (destination.pixels_half_rgba) {
- /* TODO(sergey): Consider adding specialization to avoid per-pixel overlay check. */
-
- if (destination.num_components == 1) {
- run_get_pass_kernel_processor_half_rgba(&kfilm_convert,
- render_buffers,
- buffer_params,
- destination,
- [&processor](const KernelFilmConvert *kfilm_convert,
- ccl_global const float *buffer,
- float *pixel_rgba) {
- float pixel;
- processor(kfilm_convert, buffer, &pixel);
-
- pixel_rgba[0] = pixel;
- pixel_rgba[1] = pixel;
- pixel_rgba[2] = pixel;
- pixel_rgba[3] = 1.0f;
- });
- }
- else if (destination.num_components == 3) {
- run_get_pass_kernel_processor_half_rgba(&kfilm_convert,
- render_buffers,
- buffer_params,
- destination,
- [&processor](const KernelFilmConvert *kfilm_convert,
- ccl_global const float *buffer,
- float *pixel_rgba) {
- processor(kfilm_convert, buffer, pixel_rgba);
- pixel_rgba[3] = 1.0f;
- });
- }
- else if (destination.num_components == 4) {
- run_get_pass_kernel_processor_half_rgba(
- &kfilm_convert, render_buffers, buffer_params, destination, processor);
- }
- }
-}
-
-template<typename Processor>
inline void PassAccessorCPU::run_get_pass_kernel_processor_float(
const KernelFilmConvert *kfilm_convert,
const RenderBuffers *render_buffers,
const BufferParams &buffer_params,
const Destination &destination,
- const Processor &processor) const
+ const CPUKernels::FilmConvertFunction func) const
{
+ /* NOTE: No overlays are applied since they are not used for final renders.
+ * Can be supported via some sort of specialization to avoid code duplication. */
+
DCHECK_EQ(destination.stride, 0) << "Custom stride for float destination is not implemented.";
- const float *buffer_data = render_buffers->buffer.data();
+ const int64_t pass_stride = buffer_params.pass_stride;
+ const int64_t buffer_row_stride = buffer_params.stride * buffer_params.pass_stride;
+
+ const float *window_data = render_buffers->buffer.data() + buffer_params.window_x * pass_stride +
+ buffer_params.window_y * buffer_row_stride;
+
const int pixel_stride = destination.pixel_stride ? destination.pixel_stride :
destination.num_components;
- tbb::parallel_for(0, buffer_params.height, [&](int64_t y) {
- int64_t pixel_index = y * buffer_params.width;
- for (int64_t x = 0; x < buffer_params.width; ++x, ++pixel_index) {
- const int64_t input_pixel_offset = pixel_index * buffer_params.pass_stride;
- const float *buffer = buffer_data + input_pixel_offset;
- float *pixel = destination.pixels + (pixel_index + destination.offset) * pixel_stride;
-
- processor(kfilm_convert, buffer, pixel);
- }
+ tbb::parallel_for(0, buffer_params.window_height, [&](int64_t y) {
+ const float *buffer = window_data + y * buffer_row_stride;
+ float *pixel = destination.pixels +
+ (y * buffer_params.width + destination.offset) * pixel_stride;
+ func(kfilm_convert, buffer, pixel, buffer_params.window_width, pass_stride, pixel_stride);
});
}
-template<typename Processor>
inline void PassAccessorCPU::run_get_pass_kernel_processor_half_rgba(
const KernelFilmConvert *kfilm_convert,
const RenderBuffers *render_buffers,
const BufferParams &buffer_params,
const Destination &destination,
- const Processor &processor) const
+ const CPUKernels::FilmConvertHalfRGBAFunction func) const
{
- const float *buffer_data = render_buffers->buffer.data();
+ const int64_t pass_stride = buffer_params.pass_stride;
+ const int64_t buffer_row_stride = buffer_params.stride * buffer_params.pass_stride;
+
+ const float *window_data = render_buffers->buffer.data() + buffer_params.window_x * pass_stride +
+ buffer_params.window_y * buffer_row_stride;
half4 *dst_start = destination.pixels_half_rgba + destination.offset;
const int destination_stride = destination.stride != 0 ? destination.stride :
buffer_params.width;
- tbb::parallel_for(0, buffer_params.height, [&](int64_t y) {
- int64_t pixel_index = y * buffer_params.width;
- half4 *dst_row_start = dst_start + y * destination_stride;
- for (int64_t x = 0; x < buffer_params.width; ++x, ++pixel_index) {
- const int64_t input_pixel_offset = pixel_index * buffer_params.pass_stride;
- const float *buffer = buffer_data + input_pixel_offset;
-
- float pixel[4];
- processor(kfilm_convert, buffer, pixel);
-
- film_apply_pass_pixel_overlays_rgba(kfilm_convert, buffer, pixel);
-
- half4 *pixel_half_rgba = dst_row_start + x;
- float4_store_half(&pixel_half_rgba->x, make_float4(pixel[0], pixel[1], pixel[2], pixel[3]));
- }
+ tbb::parallel_for(0, buffer_params.window_height, [&](int64_t y) {
+ const float *buffer = window_data + y * buffer_row_stride;
+ half4 *pixel = dst_start + y * destination_stride;
+ func(kfilm_convert, buffer, pixel, buffer_params.window_width, pass_stride);
});
}
@@ -156,8 +98,25 @@ inline void PassAccessorCPU::run_get_pass_kernel_processor_half_rgba(
const BufferParams &buffer_params, \
const Destination &destination) const \
{ \
- run_get_pass_kernel_processor( \
- render_buffers, buffer_params, destination, film_get_pass_pixel_##pass); \
+ const CPUKernels &kernels = Device::get_cpu_kernels(); \
+ KernelFilmConvert kfilm_convert; \
+ init_kernel_film_convert(&kfilm_convert, buffer_params, destination); \
+\
+ if (destination.pixels) { \
+ run_get_pass_kernel_processor_float(&kfilm_convert, \
+ render_buffers, \
+ buffer_params, \
+ destination, \
+ kernels.film_convert_##pass); \
+ } \
+\
+ if (destination.pixels_half_rgba) { \
+ run_get_pass_kernel_processor_half_rgba(&kfilm_convert, \
+ render_buffers, \
+ buffer_params, \
+ destination, \
+ kernels.film_convert_half_rgba_##pass); \
+ } \
}
/* Float (scalar) passes. */
diff --git a/intern/cycles/integrator/pass_accessor_cpu.h b/intern/cycles/integrator/pass_accessor_cpu.h
index 0313dc5bb0d..9ed38ab256e 100644
--- a/intern/cycles/integrator/pass_accessor_cpu.h
+++ b/intern/cycles/integrator/pass_accessor_cpu.h
@@ -16,6 +16,8 @@
#pragma once
+#include "device/cpu/kernel.h"
+
#include "integrator/pass_accessor.h"
CCL_NAMESPACE_BEGIN
@@ -28,25 +30,19 @@ class PassAccessorCPU : public PassAccessor {
using PassAccessor::PassAccessor;
protected:
- template<typename Processor>
- inline void run_get_pass_kernel_processor(const RenderBuffers *render_buffers,
- const BufferParams &buffer_params,
- const Destination &destination,
- const Processor &processor) const;
-
- template<typename Processor>
- inline void run_get_pass_kernel_processor_float(const KernelFilmConvert *kfilm_convert,
- const RenderBuffers *render_buffers,
- const BufferParams &buffer_params,
- const Destination &destination,
- const Processor &processor) const;
+ inline void run_get_pass_kernel_processor_float(
+ const KernelFilmConvert *kfilm_convert,
+ const RenderBuffers *render_buffers,
+ const BufferParams &buffer_params,
+ const Destination &destination,
+ const CPUKernels::FilmConvertFunction func) const;
- template<typename Processor>
- inline void run_get_pass_kernel_processor_half_rgba(const KernelFilmConvert *kfilm_convert,
- const RenderBuffers *render_buffers,
- const BufferParams &buffer_params,
- const Destination &destination,
- const Processor &processor) const;
+ inline void run_get_pass_kernel_processor_half_rgba(
+ const KernelFilmConvert *kfilm_convert,
+ const RenderBuffers *render_buffers,
+ const BufferParams &buffer_params,
+ const Destination &destination,
+ const CPUKernels::FilmConvertHalfRGBAFunction func) const;
#define DECLARE_PASS_ACCESSOR(pass) \
virtual void get_pass_##pass(const RenderBuffers *render_buffers, \
diff --git a/intern/cycles/integrator/pass_accessor_gpu.cpp b/intern/cycles/integrator/pass_accessor_gpu.cpp
index eb80ba99655..3fd973749b8 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
@@ -43,38 +43,41 @@ void PassAccessorGPU::run_film_convert_kernels(DeviceKernel kernel,
KernelFilmConvert kfilm_convert;
init_kernel_film_convert(&kfilm_convert, buffer_params, destination);
- const int work_size = buffer_params.width * buffer_params.height;
+ const int work_size = buffer_params.window_width * buffer_params.window_height;
const int destination_stride = destination.stride != 0 ? destination.stride :
- buffer_params.width;
+ buffer_params.window_width;
+
+ const int offset = buffer_params.window_x * buffer_params.pass_stride +
+ buffer_params.window_y * buffer_params.stride * buffer_params.pass_stride;
if (destination.d_pixels) {
DCHECK_EQ(destination.stride, 0) << "Custom stride for float destination is not implemented.";
- void *args[] = {const_cast<KernelFilmConvert *>(&kfilm_convert),
- const_cast<device_ptr *>(&destination.d_pixels),
- const_cast<device_ptr *>(&render_buffers->buffer.device_pointer),
- const_cast<int *>(&work_size),
- const_cast<int *>(&buffer_params.width),
- const_cast<int *>(&buffer_params.offset),
- const_cast<int *>(&buffer_params.stride),
- const_cast<int *>(&destination.offset),
- const_cast<int *>(&destination_stride)};
+ DeviceKernelArguments args(&kfilm_convert,
+ &destination.d_pixels,
+ &render_buffers->buffer.device_pointer,
+ &work_size,
+ &buffer_params.window_width,
+ &offset,
+ &buffer_params.stride,
+ &destination.offset,
+ &destination_stride);
queue_->enqueue(kernel, work_size, args);
}
if (destination.d_pixels_half_rgba) {
const DeviceKernel kernel_half_float = static_cast<DeviceKernel>(kernel + 1);
- void *args[] = {const_cast<KernelFilmConvert *>(&kfilm_convert),
- const_cast<device_ptr *>(&destination.d_pixels_half_rgba),
- const_cast<device_ptr *>(&render_buffers->buffer.device_pointer),
- const_cast<int *>(&work_size),
- const_cast<int *>(&buffer_params.width),
- const_cast<int *>(&buffer_params.offset),
- const_cast<int *>(&buffer_params.stride),
- const_cast<int *>(&destination.offset),
- const_cast<int *>(&destination_stride)};
+ DeviceKernelArguments args(&kfilm_convert,
+ &destination.d_pixels_half_rgba,
+ &render_buffers->buffer.device_pointer,
+ &work_size,
+ &buffer_params.window_width,
+ &offset,
+ &buffer_params.stride,
+ &destination.offset,
+ &destination_stride);
queue_->enqueue(kernel_half_float, work_size, args);
}
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 9633d3b87d3..fd697836f52 100644
--- a/intern/cycles/integrator/path_trace.cpp
+++ b/intern/cycles/integrator/path_trace.cpp
@@ -19,16 +19,17 @@
#include "device/cpu/device.h"
#include "device/device.h"
#include "integrator/pass_accessor.h"
+#include "integrator/path_trace_display.h"
+#include "integrator/path_trace_tile.h"
#include "integrator/render_scheduler.h"
-#include "render/gpu_display.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
@@ -67,11 +68,11 @@ PathTrace::PathTrace(Device *device,
PathTrace::~PathTrace()
{
/* Destroy any GPU resource which was used for graphics interop.
- * Need to have access to the GPUDisplay as it is the only source of drawing context which is
- * used for interop. */
- if (gpu_display_) {
+ * Need to have access to the PathTraceDisplay as it is the only source of drawing context which
+ * is used for interop. */
+ if (display_) {
for (auto &&path_trace_work : path_trace_works_) {
- path_trace_work->destroy_gpu_resources(gpu_display_.get());
+ path_trace_work->destroy_gpu_resources(display_.get());
}
}
}
@@ -94,7 +95,7 @@ bool PathTrace::ready_to_reset()
{
/* The logic here is optimized for the best feedback in the viewport, which implies having a GPU
* display. Of there is no such display, the logic here will break. */
- DCHECK(gpu_display_);
+ DCHECK(display_);
/* The logic here tries to provide behavior which feels the most interactive feel to artists.
* General idea is to be able to reset as quickly as possible, while still providing interactive
@@ -114,7 +115,9 @@ bool PathTrace::ready_to_reset()
return false;
}
-void PathTrace::reset(const BufferParams &full_params, const BufferParams &big_tile_params)
+void PathTrace::reset(const BufferParams &full_params,
+ const BufferParams &big_tile_params,
+ const bool reset_rendering)
{
if (big_tile_params_.modified(big_tile_params)) {
big_tile_params_ = big_tile_params;
@@ -126,8 +129,8 @@ void PathTrace::reset(const BufferParams &full_params, const BufferParams &big_t
/* NOTE: GPU display checks for buffer modification and avoids unnecessary re-allocation.
* It is requires to inform about reset whenever it happens, so that the redraw state tracking is
* properly updated. */
- if (gpu_display_) {
- gpu_display_->reset(full_params);
+ if (display_) {
+ display_->reset(big_tile_params, reset_rendering);
}
render_state_.has_denoised_result = false;
@@ -233,42 +236,53 @@ template<typename Callback>
static void foreach_sliced_buffer_params(const vector<unique_ptr<PathTraceWork>> &path_trace_works,
const vector<WorkBalanceInfo> &work_balance_infos,
const BufferParams &buffer_params,
+ const int overscan,
const Callback &callback)
{
const int num_works = path_trace_works.size();
- const int height = buffer_params.height;
+ const int window_height = buffer_params.window_height;
int current_y = 0;
for (int i = 0; i < num_works; ++i) {
const double weight = work_balance_infos[i].weight;
- const int slice_height = max(lround(height * weight), 1);
+ const int slice_window_full_y = buffer_params.full_y + buffer_params.window_y + current_y;
+ const int slice_window_height = max(lround(window_height * weight), 1);
/* Disallow negative values to deal with situations when there are more compute devices than
* scan-lines. */
- const int remaining_height = max(0, height - current_y);
+ const int remaining_window_height = max(0, window_height - current_y);
+
+ BufferParams slice_params = buffer_params;
+
+ slice_params.full_y = max(slice_window_full_y - overscan, buffer_params.full_y);
+ slice_params.window_y = slice_window_full_y - slice_params.full_y;
- BufferParams slide_params = buffer_params;
- slide_params.full_y = buffer_params.full_y + current_y;
if (i < num_works - 1) {
- slide_params.height = min(slice_height, remaining_height);
+ slice_params.window_height = min(slice_window_height, remaining_window_height);
}
else {
- slide_params.height = remaining_height;
+ slice_params.window_height = remaining_window_height;
}
- slide_params.update_offset_stride();
+ slice_params.height = slice_params.window_y + slice_params.window_height + overscan;
+ slice_params.height = min(slice_params.height,
+ buffer_params.height + buffer_params.full_y - slice_params.full_y);
- callback(path_trace_works[i].get(), slide_params);
+ slice_params.update_offset_stride();
- current_y += slide_params.height;
+ callback(path_trace_works[i].get(), slice_params);
+
+ current_y += slice_params.window_height;
}
}
void PathTrace::update_allocated_work_buffer_params()
{
+ const int overscan = tile_manager_.get_tile_overscan();
foreach_sliced_buffer_params(path_trace_works_,
work_balance_infos_,
big_tile_params_,
+ overscan,
[](PathTraceWork *path_trace_work, const BufferParams &params) {
RenderBuffers *buffers = path_trace_work->get_render_buffers();
buffers->reset(params);
@@ -281,10 +295,16 @@ static BufferParams scale_buffer_params(const BufferParams &params, int resoluti
scaled_params.width = max(1, params.width / resolution_divider);
scaled_params.height = max(1, params.height / resolution_divider);
+
+ scaled_params.window_x = params.window_x / resolution_divider;
+ scaled_params.window_y = params.window_y / resolution_divider;
+ scaled_params.window_width = max(1, params.window_width / resolution_divider);
+ scaled_params.window_height = max(1, params.window_height / resolution_divider);
+
scaled_params.full_x = params.full_x / resolution_divider;
scaled_params.full_y = params.full_y / resolution_divider;
- scaled_params.full_width = params.full_width / resolution_divider;
- scaled_params.full_height = params.full_height / resolution_divider;
+ scaled_params.full_width = max(1, params.full_width / resolution_divider);
+ scaled_params.full_height = max(1, params.full_height / resolution_divider);
scaled_params.update_offset_stride();
@@ -299,9 +319,12 @@ void PathTrace::update_effective_work_buffer_params(const RenderWork &render_wor
const BufferParams scaled_big_tile_params = scale_buffer_params(big_tile_params_,
resolution_divider);
+ const int overscan = tile_manager_.get_tile_overscan();
+
foreach_sliced_buffer_params(path_trace_works_,
work_balance_infos_,
scaled_big_tile_params,
+ overscan,
[&](PathTraceWork *path_trace_work, const BufferParams params) {
path_trace_work->set_effective_buffer_params(
scaled_full_params, scaled_big_tile_params, params);
@@ -359,7 +382,10 @@ void PathTrace::path_trace(RenderWork &render_work)
PathTraceWork *path_trace_work = path_trace_works_[i].get();
PathTraceWork::RenderStatistics statistics;
- path_trace_work->render_samples(statistics, render_work.path_trace.start_sample, num_samples);
+ path_trace_work->render_samples(statistics,
+ render_work.path_trace.start_sample,
+ num_samples,
+ render_work.path_trace.sample_offset);
const double work_time = time_dt() - work_start_time;
work_balance_infos_[i].time_spent += work_time;
@@ -458,7 +484,11 @@ void PathTrace::set_denoiser_params(const DenoiseParams &params)
}
denoiser_ = Denoiser::create(device_, params);
- denoiser_->is_cancelled_cb = [this]() { return is_cancel_requested(); };
+
+ /* Only take into account the "immediate" cancel to have interactive rendering responding to
+ * navigation as quickly as possible, but allow to run denoiser after user hit Esc button while
+ * doing offline rendering. */
+ denoiser_->is_cancelled_cb = [this]() { return render_cancel_.is_requested; };
}
void PathTrace::set_adaptive_sampling(const AdaptiveSampling &adaptive_sampling)
@@ -535,25 +565,44 @@ void PathTrace::denoise(const RenderWork &render_work)
render_scheduler_.report_denoise_time(render_work, time_dt() - start_time);
}
-void PathTrace::set_gpu_display(unique_ptr<GPUDisplay> gpu_display)
+void PathTrace::set_output_driver(unique_ptr<OutputDriver> driver)
{
- gpu_display_ = move(gpu_display);
+ output_driver_ = move(driver);
}
-void PathTrace::clear_gpu_display()
+void PathTrace::set_display_driver(unique_ptr<DisplayDriver> driver)
{
- if (gpu_display_) {
- gpu_display_->clear();
+ if (driver) {
+ display_ = make_unique<PathTraceDisplay>(move(driver));
+ }
+ else {
+ display_ = nullptr;
+ }
+}
+
+void PathTrace::clear_display()
+{
+ if (display_) {
+ display_->clear();
}
}
void PathTrace::draw()
{
- if (!gpu_display_) {
+ if (!display_) {
+ return;
+ }
+
+ did_draw_after_reset_ |= display_->draw();
+}
+
+void PathTrace::flush_display()
+{
+ if (!display_) {
return;
}
- did_draw_after_reset_ |= gpu_display_->draw();
+ display_->flush();
}
void PathTrace::update_display(const RenderWork &render_work)
@@ -562,31 +611,31 @@ void PathTrace::update_display(const RenderWork &render_work)
return;
}
- if (!gpu_display_ && !tile_buffer_update_cb) {
+ if (!display_ && !output_driver_) {
VLOG(3) << "Ignore display update.";
return;
}
if (full_params_.width == 0 || full_params_.height == 0) {
- VLOG(3) << "Skipping GPUDisplay update due to 0 size of the render buffer.";
+ VLOG(3) << "Skipping PathTraceDisplay update due to 0 size of the render buffer.";
return;
}
const double start_time = time_dt();
- if (tile_buffer_update_cb) {
+ if (output_driver_) {
VLOG(3) << "Invoke buffer update callback.";
- tile_buffer_update_cb();
+ PathTraceTile tile(*this);
+ output_driver_->update_render_tile(tile);
}
- if (gpu_display_) {
+ if (display_) {
VLOG(3) << "Perform copy to GPUDisplay work.";
- const int resolution_divider = render_work.resolution_divider;
- const int texture_width = max(1, full_params_.width / resolution_divider);
- const int texture_height = max(1, full_params_.height / resolution_divider);
- if (!gpu_display_->update_begin(texture_width, texture_height)) {
+ const int texture_width = render_state_.effective_big_tile_params.window_width;
+ const int texture_height = render_state_.effective_big_tile_params.window_height;
+ if (!display_->update_begin(texture_width, texture_height)) {
LOG(ERROR) << "Error beginning GPUDisplay update.";
return;
}
@@ -600,10 +649,10 @@ void PathTrace::update_display(const RenderWork &render_work)
* all works in parallel. */
const int num_samples = get_num_samples_in_buffer();
for (auto &&path_trace_work : path_trace_works_) {
- path_trace_work->copy_to_gpu_display(gpu_display_.get(), pass_mode, num_samples);
+ path_trace_work->copy_to_display(display_.get(), pass_mode, num_samples);
}
- gpu_display_->update_end();
+ display_->update_end();
}
render_scheduler_.report_display_update_time(render_work, time_dt() - start_time);
@@ -753,20 +802,33 @@ bool PathTrace::is_cancel_requested()
void PathTrace::tile_buffer_write()
{
- if (!tile_buffer_write_cb) {
+ if (!output_driver_) {
return;
}
- tile_buffer_write_cb();
+ PathTraceTile tile(*this);
+ output_driver_->write_render_tile(tile);
}
void PathTrace::tile_buffer_read()
{
- if (!tile_buffer_read_cb) {
+ if (!device_scene_->data.bake.use) {
+ return;
+ }
+
+ if (!output_driver_) {
return;
}
- if (tile_buffer_read_cb()) {
+ /* Read buffers back from device. */
+ tbb::parallel_for_each(path_trace_works_, [&](unique_ptr<PathTraceWork> &path_trace_work) {
+ path_trace_work->copy_render_buffers_from_device();
+ });
+
+ /* Read (subset of) passes from output driver. */
+ PathTraceTile tile(*this);
+ if (output_driver_->read_render_tile(tile)) {
+ /* Copy buffers to device again. */
tbb::parallel_for_each(path_trace_works_, [](unique_ptr<PathTraceWork> &path_trace_work) {
path_trace_work->copy_render_buffers_to_device();
});
@@ -809,9 +871,11 @@ void PathTrace::progress_update_if_needed(const RenderWork &render_work)
{
if (progress_ != nullptr) {
const int2 tile_size = get_render_tile_size();
- const int num_samples_added = tile_size.x * tile_size.y * render_work.path_trace.num_samples;
+ const uint64_t num_samples_added = uint64_t(tile_size.x) * tile_size.y *
+ render_work.path_trace.num_samples;
const int current_sample = render_work.path_trace.start_sample +
- render_work.path_trace.num_samples;
+ render_work.path_trace.num_samples -
+ render_work.path_trace.sample_offset;
progress_->add_samples(num_samples_added, current_sample);
}
@@ -987,12 +1051,12 @@ bool PathTrace::set_render_tile_pixels(PassAccessor &pass_accessor,
int2 PathTrace::get_render_tile_size() const
{
if (full_frame_state_.render_buffers) {
- return make_int2(full_frame_state_.render_buffers->params.width,
- full_frame_state_.render_buffers->params.height);
+ return make_int2(full_frame_state_.render_buffers->params.window_width,
+ full_frame_state_.render_buffers->params.window_height);
}
const Tile &tile = tile_manager_.get_current_tile();
- return make_int2(tile.width, tile.height);
+ return make_int2(tile.window_width, tile.window_height);
}
int2 PathTrace::get_render_tile_offset() const
@@ -1002,7 +1066,12 @@ int2 PathTrace::get_render_tile_offset() const
}
const Tile &tile = tile_manager_.get_current_tile();
- return make_int2(tile.x, tile.y);
+ return make_int2(tile.x + tile.window_x, tile.y + tile.window_y);
+}
+
+int2 PathTrace::get_render_size() const
+{
+ return tile_manager_.get_size();
}
const BufferParams &PathTrace::get_render_tile_params() const
@@ -1041,6 +1110,8 @@ static const char *device_type_for_description(const DeviceType type)
return "Dummy";
case DEVICE_MULTI:
return "Multi";
+ case DEVICE_METAL:
+ return "Metal";
}
return "UNKNOWN";
diff --git a/intern/cycles/integrator/path_trace.h b/intern/cycles/integrator/path_trace.h
index f507c2d7e0a..bb41c8c3210 100644
--- a/intern/cycles/integrator/path_trace.h
+++ b/intern/cycles/integrator/path_trace.h
@@ -20,23 +20,25 @@
#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
class AdaptiveSampling;
class Device;
class DeviceScene;
+class DisplayDriver;
class Film;
class RenderBuffers;
class RenderScheduler;
class RenderWork;
+class PathTraceDisplay;
+class OutputDriver;
class Progress;
-class GPUDisplay;
class TileManager;
/* PathTrace class takes care of kernel graph and scheduling on a (multi)device. It takes care of
@@ -70,7 +72,9 @@ class PathTrace {
* render result. */
bool ready_to_reset();
- void reset(const BufferParams &full_params, const BufferParams &big_tile_params);
+ void reset(const BufferParams &full_params,
+ const BufferParams &big_tile_params,
+ bool reset_rendering);
void device_free();
@@ -98,15 +102,21 @@ class PathTrace {
* Use this to configure the adaptive sampler before rendering any samples. */
void set_adaptive_sampling(const AdaptiveSampling &adaptive_sampling);
- /* Set GPU display which takes care of drawing the render result. */
- void set_gpu_display(unique_ptr<GPUDisplay> gpu_display);
+ /* Sets output driver for render buffer output. */
+ void set_output_driver(unique_ptr<OutputDriver> driver);
- /* Clear the GPU display by filling it in with all zeroes. */
- void clear_gpu_display();
+ /* Set display driver for interactive render buffer display. */
+ void set_display_driver(unique_ptr<DisplayDriver> driver);
- /* Perform drawing of the current state of the GPUDisplay. */
+ /* Clear the display buffer by filling it in with all zeroes. */
+ void clear_display();
+
+ /* Perform drawing of the current state of the DisplayDriver. */
void draw();
+ /* Flush outstanding display commands before ending the render loop. */
+ void flush_display();
+
/* Cancel rendering process as soon as possible, without waiting for full tile to be sampled.
* Used in cases like reset of render session.
*
@@ -157,6 +167,7 @@ class PathTrace {
* instead. */
int2 get_render_tile_size() const;
int2 get_render_tile_offset() const;
+ int2 get_render_size() const;
/* Get buffer parameters of the current tile.
*
@@ -168,18 +179,6 @@ class PathTrace {
* times, and so on. */
string full_report() const;
- /* Callback which communicates an updates state of the render buffer of the current big tile.
- * Is called during path tracing to communicate work-in-progress state of the final buffer. */
- function<void(void)> tile_buffer_update_cb;
-
- /* Callback which communicates final rendered buffer. Is called after path-tracing is done. */
- function<void(void)> tile_buffer_write_cb;
-
- /* Callback which initializes rendered buffer. Is called before path-tracing starts.
- *
- * This is used for baking. */
- function<bool(void)> tile_buffer_read_cb;
-
/* Callback which is called to report current rendering progress.
*
* It is supposed to be cheaper than buffer update/write, hence can be called more often.
@@ -252,7 +251,11 @@ class PathTrace {
RenderScheduler &render_scheduler_;
TileManager &tile_manager_;
- unique_ptr<GPUDisplay> gpu_display_;
+ /* Display driver for interactive render buffer display. */
+ unique_ptr<PathTraceDisplay> display_;
+
+ /* Output driver to write render buffer to. */
+ unique_ptr<OutputDriver> output_driver_;
/* Per-compute device descriptors of work which is responsible for path tracing on its configured
* device. */
diff --git a/intern/cycles/integrator/path_trace_display.cpp b/intern/cycles/integrator/path_trace_display.cpp
new file mode 100644
index 00000000000..4af622065c2
--- /dev/null
+++ b/intern/cycles/integrator/path_trace_display.cpp
@@ -0,0 +1,261 @@
+/*
+ * 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 "integrator/path_trace_display.h"
+
+#include "session/buffers.h"
+
+#include "util/log.h"
+
+CCL_NAMESPACE_BEGIN
+
+PathTraceDisplay::PathTraceDisplay(unique_ptr<DisplayDriver> driver) : driver_(move(driver))
+{
+}
+
+void PathTraceDisplay::reset(const BufferParams &buffer_params, const bool reset_rendering)
+{
+ thread_scoped_lock lock(mutex_);
+
+ params_.full_offset = make_int2(buffer_params.full_x + buffer_params.window_x,
+ buffer_params.full_y + buffer_params.window_y);
+ params_.full_size = make_int2(buffer_params.full_width, buffer_params.full_height);
+ params_.size = make_int2(buffer_params.window_width, buffer_params.window_height);
+
+ texture_state_.is_outdated = true;
+
+ if (!reset_rendering) {
+ driver_->next_tile_begin();
+ }
+}
+
+void PathTraceDisplay::mark_texture_updated()
+{
+ texture_state_.is_outdated = false;
+}
+
+/* --------------------------------------------------------------------
+ * Update procedure.
+ */
+
+bool PathTraceDisplay::update_begin(int texture_width, int texture_height)
+{
+ DCHECK(!update_state_.is_active);
+
+ if (update_state_.is_active) {
+ LOG(ERROR) << "Attempt to re-activate update process.";
+ return false;
+ }
+
+ /* Get parameters within a mutex lock, to avoid reset() modifying them at the same time.
+ * The update itself is non-blocking however, for better performance and to avoid
+ * potential deadlocks due to locks held by the subclass. */
+ DisplayDriver::Params params;
+ {
+ thread_scoped_lock lock(mutex_);
+ params = params_;
+ texture_state_.size = make_int2(texture_width, texture_height);
+ }
+
+ if (!driver_->update_begin(params, texture_width, texture_height)) {
+ LOG(ERROR) << "PathTraceDisplay implementation could not begin update.";
+ return false;
+ }
+
+ update_state_.is_active = true;
+
+ return true;
+}
+
+void PathTraceDisplay::update_end()
+{
+ DCHECK(update_state_.is_active);
+
+ if (!update_state_.is_active) {
+ LOG(ERROR) << "Attempt to deactivate inactive update process.";
+ return;
+ }
+
+ driver_->update_end();
+
+ update_state_.is_active = false;
+}
+
+int2 PathTraceDisplay::get_texture_size() const
+{
+ return texture_state_.size;
+}
+
+/* --------------------------------------------------------------------
+ * Texture update from CPU buffer.
+ */
+
+void PathTraceDisplay::copy_pixels_to_texture(
+ const half4 *rgba_pixels, int texture_x, int texture_y, int pixels_width, int pixels_height)
+{
+ DCHECK(update_state_.is_active);
+
+ if (!update_state_.is_active) {
+ LOG(ERROR) << "Attempt to copy pixels data outside of PathTraceDisplay update.";
+ return;
+ }
+
+ mark_texture_updated();
+
+ /* This call copies pixels to a mapped texture buffer which is typically much cheaper from CPU
+ * time point of view than to copy data directly to a texture.
+ *
+ * The possible downside of this approach is that it might require a higher peak memory when
+ * doing partial updates of the texture (although, in practice even partial updates might peak
+ * with a full-frame buffer stored on the CPU if the GPU is currently occupied). */
+ half4 *mapped_rgba_pixels = map_texture_buffer();
+ if (!mapped_rgba_pixels) {
+ return;
+ }
+
+ const int texture_width = texture_state_.size.x;
+ const int texture_height = texture_state_.size.y;
+
+ if (texture_x == 0 && texture_y == 0 && pixels_width == texture_width &&
+ pixels_height == texture_height) {
+ const size_t size_in_bytes = sizeof(half4) * texture_width * texture_height;
+ memcpy(mapped_rgba_pixels, rgba_pixels, size_in_bytes);
+ }
+ else {
+ const half4 *rgba_row = rgba_pixels;
+ half4 *mapped_rgba_row = mapped_rgba_pixels + texture_y * texture_width + texture_x;
+ for (int y = 0; y < pixels_height;
+ ++y, rgba_row += pixels_width, mapped_rgba_row += texture_width) {
+ memcpy(mapped_rgba_row, rgba_row, sizeof(half4) * pixels_width);
+ }
+ }
+
+ unmap_texture_buffer();
+}
+
+/* --------------------------------------------------------------------
+ * Texture buffer mapping.
+ */
+
+half4 *PathTraceDisplay::map_texture_buffer()
+{
+ DCHECK(!texture_buffer_state_.is_mapped);
+ DCHECK(update_state_.is_active);
+
+ if (texture_buffer_state_.is_mapped) {
+ LOG(ERROR) << "Attempt to re-map an already mapped texture buffer.";
+ return nullptr;
+ }
+
+ if (!update_state_.is_active) {
+ LOG(ERROR) << "Attempt to copy pixels data outside of PathTraceDisplay update.";
+ return nullptr;
+ }
+
+ half4 *mapped_rgba_pixels = driver_->map_texture_buffer();
+
+ if (mapped_rgba_pixels) {
+ texture_buffer_state_.is_mapped = true;
+ }
+
+ return mapped_rgba_pixels;
+}
+
+void PathTraceDisplay::unmap_texture_buffer()
+{
+ DCHECK(texture_buffer_state_.is_mapped);
+
+ if (!texture_buffer_state_.is_mapped) {
+ LOG(ERROR) << "Attempt to unmap non-mapped texture buffer.";
+ return;
+ }
+
+ texture_buffer_state_.is_mapped = false;
+
+ mark_texture_updated();
+ driver_->unmap_texture_buffer();
+}
+
+/* --------------------------------------------------------------------
+ * Graphics interoperability.
+ */
+
+DisplayDriver::GraphicsInterop PathTraceDisplay::graphics_interop_get()
+{
+ DCHECK(!texture_buffer_state_.is_mapped);
+ DCHECK(update_state_.is_active);
+
+ if (texture_buffer_state_.is_mapped) {
+ LOG(ERROR)
+ << "Attempt to use graphics interoperability mode while the texture buffer is mapped.";
+ return DisplayDriver::GraphicsInterop();
+ }
+
+ if (!update_state_.is_active) {
+ LOG(ERROR) << "Attempt to use graphics interoperability outside of PathTraceDisplay update.";
+ return DisplayDriver::GraphicsInterop();
+ }
+
+ /* Assume that interop will write new values to the texture. */
+ mark_texture_updated();
+
+ return driver_->graphics_interop_get();
+}
+
+void PathTraceDisplay::graphics_interop_activate()
+{
+ driver_->graphics_interop_activate();
+}
+
+void PathTraceDisplay::graphics_interop_deactivate()
+{
+ driver_->graphics_interop_deactivate();
+}
+
+/* --------------------------------------------------------------------
+ * Drawing.
+ */
+
+void PathTraceDisplay::clear()
+{
+ driver_->clear();
+}
+
+bool PathTraceDisplay::draw()
+{
+ /* Get parameters within a mutex lock, to avoid reset() modifying them at the same time.
+ * 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_outdated;
+
+ {
+ thread_scoped_lock lock(mutex_);
+ params = params_;
+ is_outdated = texture_state_.is_outdated;
+ }
+
+ driver_->draw(params);
+
+ return !is_outdated;
+}
+
+void PathTraceDisplay::flush()
+{
+ driver_->flush();
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/integrator/path_trace_display.h b/intern/cycles/integrator/path_trace_display.h
new file mode 100644
index 00000000000..906d7d54029
--- /dev/null
+++ b/intern/cycles/integrator/path_trace_display.h
@@ -0,0 +1,198 @@
+/*
+ * 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 "session/display_driver.h"
+
+#include "util/half.h"
+#include "util/thread.h"
+#include "util/types.h"
+#include "util/unique_ptr.h"
+
+CCL_NAMESPACE_BEGIN
+
+class BufferParams;
+
+/* PathTraceDisplay is used for efficient render buffer display.
+ *
+ * The host applications implements a DisplayDriver, storing a render pass in a GPU-side
+ * textures. This texture is continuously updated by the path tracer and drawn by the host
+ * application.
+ *
+ * PathTraceDisplay is a wrapper around the DisplayDriver, adding thread safety, state tracking
+ * and error checking. */
+
+class PathTraceDisplay {
+ public:
+ explicit PathTraceDisplay(unique_ptr<DisplayDriver> driver);
+ virtual ~PathTraceDisplay() = default;
+
+ /* Reset the display for the new state of render session. Is called whenever session is reset,
+ * which happens on changes like viewport navigation or viewport dimension change.
+ *
+ * This call will configure parameters for a changed buffer and reset the texture state.
+ *
+ * When the `reset_rendering` a complete display reset happens. When it is false reset happens
+ * for a new state of the buffer parameters which is assumed to correspond to the next tile. */
+ void reset(const BufferParams &buffer_params, bool reset_rendering);
+
+ /* --------------------------------------------------------------------
+ * Update procedure.
+ *
+ * These calls indicates a desire of the caller to update content of the displayed texture. */
+
+ /* Returns true when update is ready. Update should be finished with update_end().
+ *
+ * If false is returned then no update is possible, and no update_end() call is needed.
+ *
+ * The texture width and height denotes an actual resolution of the underlying render result. */
+ bool update_begin(int texture_width, int texture_height);
+
+ void update_end();
+
+ /* Get currently configured texture size of the display (as configured by `update_begin()`. */
+ int2 get_texture_size() const;
+
+ /* --------------------------------------------------------------------
+ * Texture update from CPU buffer.
+ *
+ * NOTE: The PathTraceDisplay should be marked for an update being in process with
+ * `update_begin()`.
+ *
+ * Most portable implementation, which must be supported by all platforms. Might not be the most
+ * efficient one.
+ */
+
+ /* Copy buffer of rendered pixels of a given size into a given position of the texture.
+ *
+ * This function does not acquire a lock. The reason for this is to allow use of this function
+ * for partial updates from different devices. In this case the caller will acquire the lock
+ * once, update all the slices and release
+ * the lock once. This will ensure that draw() will never use partially updated texture. */
+ void copy_pixels_to_texture(
+ const half4 *rgba_pixels, int texture_x, int texture_y, int pixels_width, int pixels_height);
+
+ /* --------------------------------------------------------------------
+ * Texture buffer mapping.
+ *
+ * This functionality is used to update GPU-side texture content without need to maintain CPU
+ * side buffer on the caller.
+ *
+ * NOTE: The PathTraceDisplay should be marked for an update being in process with
+ * `update_begin()`.
+ *
+ * NOTE: Texture buffer can not be mapped while graphics interoperability is active. This means
+ * that `map_texture_buffer()` is not allowed between `graphics_interop_begin()` and
+ * `graphics_interop_end()` calls.
+ */
+
+ /* Map pixels memory form texture to a buffer available for write from CPU. Width and height will
+ * define a requested size of the texture to write to.
+ * Upon success a non-null pointer is returned and the texture buffer is to be unmapped.
+ * If an error happens during mapping, or if mapping is not supported by this GPU display a
+ * null pointer is returned and the buffer is NOT to be unmapped.
+ *
+ * NOTE: Usually the implementation will rely on a GPU context of some sort, and the GPU context
+ * is often can not be bound to two threads simultaneously, and can not be released from a
+ * different thread. This means that the mapping API should be used from the single thread only,
+ */
+ half4 *map_texture_buffer();
+ void unmap_texture_buffer();
+
+ /* --------------------------------------------------------------------
+ * Graphics interoperability.
+ *
+ * A special code path which allows to update texture content directly from the GPU compute
+ * device. Complementary part of DeviceGraphicsInterop.
+ *
+ * NOTE: Graphics interoperability can not be used while the texture buffer is mapped. This means
+ * that `graphics_interop_get()` is not allowed between `map_texture_buffer()` and
+ * `unmap_texture_buffer()` calls. */
+
+ /* Get PathTraceDisplay graphics interoperability information which acts as a destination for the
+ * device API. */
+ DisplayDriver::GraphicsInterop graphics_interop_get();
+
+ /* (De)activate GPU display for graphics interoperability outside of regular display update
+ * routines. */
+ void graphics_interop_activate();
+ void graphics_interop_deactivate();
+
+ /* --------------------------------------------------------------------
+ * Drawing.
+ */
+
+ /* Clear the texture by filling it with all zeroes.
+ *
+ * This call might happen in parallel with draw, but can never happen in parallel with the
+ * update.
+ *
+ * The actual zeroing can be deferred to a later moment. What is important is that after clear
+ * and before pixels update the drawing texture will be fully empty, and that partial update
+ * after clear will write new pixel values for an updating area, leaving everything else zeroed.
+ *
+ * If the GPU display supports graphics interoperability then the zeroing the display is to be
+ * delegated to the device via the `DisplayDriver::GraphicsInterop`. */
+ void clear();
+
+ /* Draw the current state of the texture.
+ *
+ * Returns true if this call did draw an updated state of the texture. */
+ bool draw();
+
+ /* Flush outstanding display commands before ending the render loop. */
+ void flush();
+
+ private:
+ /* Display driver implemented by the host application. */
+ unique_ptr<DisplayDriver> driver_;
+
+ /* Current display parameters */
+ thread_mutex mutex_;
+ DisplayDriver::Params params_;
+
+ /* Mark texture as its content has been updated.
+ * Used from places which knows that the texture content has been brought up-to-date, so that the
+ * drawing knows whether it can be performed, and whether drawing happened with an up-to-date
+ * texture state. */
+ void mark_texture_updated();
+
+ /* State of the update process. */
+ struct {
+ /* True when update is in process, indicated by `update_begin()` / `update_end()`. */
+ bool is_active = false;
+ } update_state_;
+
+ /* State of the texture, which is needed for an integration with render session and interactive
+ * updates and navigation. */
+ struct {
+ /* Texture is considered outdated after `reset()` until the next call of
+ * `copy_pixels_to_texture()`. */
+ bool is_outdated = true;
+
+ /* Texture size in pixels. */
+ int2 size = make_int2(0, 0);
+ } texture_state_;
+
+ /* State of the texture buffer. Is tracked to perform sanity checks. */
+ struct {
+ /* True when the texture buffer is mapped with `map_texture_buffer()`. */
+ bool is_mapped = false;
+ } texture_buffer_state_;
+};
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/integrator/path_trace_tile.cpp b/intern/cycles/integrator/path_trace_tile.cpp
new file mode 100644
index 00000000000..4834769f476
--- /dev/null
+++ b/intern/cycles/integrator/path_trace_tile.cpp
@@ -0,0 +1,107 @@
+/*
+ * 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 "integrator/path_trace_tile.h"
+#include "integrator/pass_accessor_cpu.h"
+#include "integrator/path_trace.h"
+
+#include "scene/film.h"
+#include "scene/pass.h"
+#include "scene/scene.h"
+#include "session/buffers.h"
+
+CCL_NAMESPACE_BEGIN
+
+PathTraceTile::PathTraceTile(PathTrace &path_trace)
+ : OutputDriver::Tile(path_trace.get_render_tile_offset(),
+ path_trace.get_render_tile_size(),
+ path_trace.get_render_size(),
+ path_trace.get_render_tile_params().layer,
+ path_trace.get_render_tile_params().view),
+ path_trace_(path_trace),
+ copied_from_device_(false)
+{
+}
+
+bool PathTraceTile::get_pass_pixels(const string_view pass_name,
+ const int num_channels,
+ float *pixels) const
+{
+ /* NOTE: The code relies on a fact that session is fully update and no scene/buffer modification
+ * is happening while this function runs. */
+
+ if (!copied_from_device_) {
+ /* Copy from device on demand. */
+ path_trace_.copy_render_tile_from_device();
+ const_cast<PathTraceTile *>(this)->copied_from_device_ = true;
+ }
+
+ const BufferParams &buffer_params = path_trace_.get_render_tile_params();
+
+ const BufferPass *pass = buffer_params.find_pass(pass_name);
+ if (pass == nullptr) {
+ return false;
+ }
+
+ const bool has_denoised_result = path_trace_.has_denoised_result();
+ if (pass->mode == PassMode::DENOISED && !has_denoised_result) {
+ pass = buffer_params.find_pass(pass->type);
+ if (pass == nullptr) {
+ /* Happens when denoised result pass is requested but is never written by the kernel. */
+ return false;
+ }
+ }
+
+ pass = buffer_params.get_actual_display_pass(pass);
+
+ const float exposure = buffer_params.exposure;
+ const int num_samples = path_trace_.get_num_render_tile_samples();
+
+ PassAccessor::PassAccessInfo pass_access_info(*pass);
+ pass_access_info.use_approximate_shadow_catcher = buffer_params.use_approximate_shadow_catcher;
+ pass_access_info.use_approximate_shadow_catcher_background =
+ pass_access_info.use_approximate_shadow_catcher && !buffer_params.use_transparent_background;
+
+ const PassAccessorCPU pass_accessor(pass_access_info, exposure, num_samples);
+ const PassAccessor::Destination destination(pixels, num_channels);
+
+ return path_trace_.get_render_tile_pixels(pass_accessor, destination);
+}
+
+bool PathTraceTile::set_pass_pixels(const string_view pass_name,
+ const int num_channels,
+ const float *pixels) const
+{
+ /* NOTE: The code relies on a fact that session is fully update and no scene/buffer modification
+ * is happening while this function runs. */
+
+ const BufferParams &buffer_params = path_trace_.get_render_tile_params();
+ const BufferPass *pass = buffer_params.find_pass(pass_name);
+ if (!pass) {
+ return false;
+ }
+
+ const float exposure = buffer_params.exposure;
+ const int num_samples = 1;
+
+ const PassAccessor::PassAccessInfo pass_access_info(*pass);
+ PassAccessorCPU pass_accessor(pass_access_info, exposure, num_samples);
+ PassAccessor::Source source(pixels, num_channels);
+
+ return path_trace_.set_render_tile_pixels(pass_accessor, source);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/integrator/path_trace_tile.h b/intern/cycles/integrator/path_trace_tile.h
new file mode 100644
index 00000000000..6c7bddf2ca5
--- /dev/null
+++ b/intern/cycles/integrator/path_trace_tile.h
@@ -0,0 +1,43 @@
+/*
+ * 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 "session/output_driver.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* PathTraceTile
+ *
+ * Implementation of OutputDriver::Tile interface for path tracer. */
+
+class PathTrace;
+
+class PathTraceTile : public OutputDriver::Tile {
+ public:
+ PathTraceTile(PathTrace &path_trace);
+
+ bool get_pass_pixels(const string_view pass_name, const int num_channels, float *pixels) const;
+ bool set_pass_pixels(const string_view pass_name,
+ const int num_channels,
+ const float *pixels) const;
+
+ private:
+ PathTrace &path_trace_;
+ bool copied_from_device_;
+};
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/integrator/path_trace_work.cpp b/intern/cycles/integrator/path_trace_work.cpp
index d9634acac10..4ecc7d775ee 100644
--- a/intern/cycles/integrator/path_trace_work.cpp
+++ b/intern/cycles/integrator/path_trace_work.cpp
@@ -16,15 +16,15 @@
#include "device/device.h"
+#include "integrator/path_trace_display.h"
#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/gpu_display.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
@@ -134,7 +134,8 @@ void PathTraceWork::copy_from_denoised_render_buffers(const RenderBuffers *rende
bool PathTraceWork::get_render_tile_pixels(const PassAccessor &pass_accessor,
const PassAccessor::Destination &destination)
{
- const int offset_y = effective_buffer_params_.full_y - effective_big_tile_params_.full_y;
+ const int offset_y = (effective_buffer_params_.full_y + effective_buffer_params_.window_y) -
+ (effective_big_tile_params_.full_y + effective_big_tile_params_.window_y);
const int width = effective_buffer_params_.width;
PassAccessor::Destination slice_destination = destination;
@@ -182,17 +183,21 @@ PassAccessor::PassAccessInfo PathTraceWork::get_display_pass_access_info(PassMod
pass_access_info.use_approximate_shadow_catcher_background =
kfilm.use_approximate_shadow_catcher && !kbackground.transparent;
+ pass_access_info.show_active_pixels = film_->get_show_active_pixels();
+
return pass_access_info;
}
-PassAccessor::Destination PathTraceWork::get_gpu_display_destination_template(
- const GPUDisplay *gpu_display) const
+PassAccessor::Destination PathTraceWork::get_display_destination_template(
+ const PathTraceDisplay *display) const
{
PassAccessor::Destination destination(film_->get_display_pass());
- const int2 display_texture_size = gpu_display->get_texture_size();
- const int texture_x = effective_buffer_params_.full_x - effective_full_params_.full_x;
- const int texture_y = effective_buffer_params_.full_y - effective_full_params_.full_y;
+ const int2 display_texture_size = display->get_texture_size();
+ const int texture_x = effective_buffer_params_.full_x - effective_big_tile_params_.full_x +
+ effective_buffer_params_.window_x - effective_big_tile_params_.window_x;
+ const int texture_y = effective_buffer_params_.full_y - effective_big_tile_params_.full_y +
+ effective_buffer_params_.window_y - effective_big_tile_params_.window_y;
destination.offset = texture_y * display_texture_size.x + texture_x;
destination.stride = display_texture_size.x;
diff --git a/intern/cycles/integrator/path_trace_work.h b/intern/cycles/integrator/path_trace_work.h
index e1be1655edd..2ebfc913580 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
@@ -28,7 +28,7 @@ class BufferParams;
class Device;
class DeviceScene;
class Film;
-class GPUDisplay;
+class PathTraceDisplay;
class RenderBuffers;
class PathTraceWork {
@@ -75,7 +75,10 @@ class PathTraceWork {
/* Render given number of samples as a synchronous blocking call.
* The samples are added to the render buffer associated with this work. */
- virtual void render_samples(RenderStatistics &statistics, int start_sample, int samples_num) = 0;
+ virtual void render_samples(RenderStatistics &statistics,
+ int start_sample,
+ int samples_num,
+ int sample_offset) = 0;
/* Copy render result from this work to the corresponding place of the GPU display.
*
@@ -83,11 +86,9 @@ class PathTraceWork {
* noisy pass mode will be passed here when it is known that the buffer does not have denoised
* passes yet (because denoiser did not run). If the denoised pass is requested and denoiser is
* not used then this function will fall-back to the noisy pass instead. */
- virtual void copy_to_gpu_display(GPUDisplay *gpu_display,
- PassMode pass_mode,
- int num_samples) = 0;
+ virtual void copy_to_display(PathTraceDisplay *display, PassMode pass_mode, int num_samples) = 0;
- virtual void destroy_gpu_resources(GPUDisplay *gpu_display) = 0;
+ virtual void destroy_gpu_resources(PathTraceDisplay *display) = 0;
/* Copy data from/to given render buffers.
* Will copy pixels from a corresponding place (from multi-device point of view) of the render
@@ -162,8 +163,8 @@ class PathTraceWork {
/* Get destination which offset and stride are configured so that writing to it will write to a
* proper location of GPU display texture, taking current tile and device slice into account. */
- PassAccessor::Destination get_gpu_display_destination_template(
- const GPUDisplay *gpu_display) const;
+ PassAccessor::Destination get_display_destination_template(
+ const PathTraceDisplay *display) const;
/* Device which will be used for path tracing.
* Note that it is an actual render device (and never is a multi-device). */
diff --git a/intern/cycles/integrator/path_trace_work_cpu.cpp b/intern/cycles/integrator/path_trace_work_cpu.cpp
index b9a33b64051..2f6c3cf5aca 100644
--- a/intern/cycles/integrator/path_trace_work_cpu.cpp
+++ b/intern/cycles/integrator/path_trace_work_cpu.cpp
@@ -19,15 +19,17 @@
#include "device/cpu/kernel.h"
#include "device/device.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/gpu_display.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
@@ -56,7 +58,7 @@ PathTraceWorkCPU::PathTraceWorkCPU(Device *device,
DeviceScene *device_scene,
bool *cancel_requested_flag)
: PathTraceWork(device, film, device_scene, cancel_requested_flag),
- kernels_(*(device->get_cpu_kernels()))
+ kernels_(Device::get_cpu_kernels())
{
DCHECK_EQ(device->info.type, DEVICE_CPU);
}
@@ -69,14 +71,17 @@ void PathTraceWorkCPU::init_execution()
void PathTraceWorkCPU::render_samples(RenderStatistics &statistics,
int start_sample,
- int samples_num)
+ int samples_num,
+ int sample_offset)
{
const int64_t image_width = effective_buffer_params_.width;
const int64_t image_height = effective_buffer_params_.height;
const int64_t total_pixels_num = image_width * image_height;
- for (CPUKernelThreadGlobals &kernel_globals : kernel_thread_globals_) {
- kernel_globals.start_profiling();
+ if (device_->profiler.active()) {
+ for (CPUKernelThreadGlobals &kernel_globals : kernel_thread_globals_) {
+ kernel_globals.start_profiling();
+ }
}
tbb::task_arena local_arena = local_tbb_arena_create(device_);
@@ -95,6 +100,7 @@ void PathTraceWorkCPU::render_samples(RenderStatistics &statistics,
work_tile.w = 1;
work_tile.h = 1;
work_tile.start_sample = start_sample;
+ work_tile.sample_offset = sample_offset;
work_tile.num_samples = 1;
work_tile.offset = effective_buffer_params_.offset;
work_tile.stride = effective_buffer_params_.stride;
@@ -104,25 +110,30 @@ void PathTraceWorkCPU::render_samples(RenderStatistics &statistics,
render_samples_full_pipeline(kernel_globals, work_tile, samples_num);
});
});
-
- for (CPUKernelThreadGlobals &kernel_globals : kernel_thread_globals_) {
- kernel_globals.stop_profiling();
+ if (device_->profiler.active()) {
+ for (CPUKernelThreadGlobals &kernel_globals : kernel_thread_globals_) {
+ kernel_globals.stop_profiling();
+ }
}
statistics.occupancy = 1.0f;
}
-void PathTraceWorkCPU::render_samples_full_pipeline(KernelGlobals *kernel_globals,
+void PathTraceWorkCPU::render_samples_full_pipeline(KernelGlobalsCPU *kernel_globals,
const KernelWorkTile &work_tile,
const int samples_num)
{
- const bool has_shadow_catcher = device_scene_->data.integrator.has_shadow_catcher;
const bool has_bake = device_scene_->data.bake.use;
- IntegratorStateCPU integrator_states[2] = {};
+ IntegratorStateCPU integrator_states[2];
IntegratorStateCPU *state = &integrator_states[0];
- IntegratorStateCPU *shadow_catcher_state = &integrator_states[1];
+ IntegratorStateCPU *shadow_catcher_state = nullptr;
+
+ if (device_scene_->data.integrator.has_shadow_catcher) {
+ shadow_catcher_state = &integrator_states[1];
+ path_state_init_queues(shadow_catcher_state);
+ }
KernelWorkTile sample_work_tile = work_tile;
float *render_buffer = buffers_->buffer.data();
@@ -147,7 +158,7 @@ void PathTraceWorkCPU::render_samples_full_pipeline(KernelGlobals *kernel_global
kernels_.integrator_megakernel(kernel_globals, state, render_buffer);
- if (has_shadow_catcher) {
+ if (shadow_catcher_state) {
kernels_.integrator_megakernel(kernel_globals, shadow_catcher_state, render_buffer);
}
@@ -155,14 +166,14 @@ void PathTraceWorkCPU::render_samples_full_pipeline(KernelGlobals *kernel_global
}
}
-void PathTraceWorkCPU::copy_to_gpu_display(GPUDisplay *gpu_display,
- PassMode pass_mode,
- int num_samples)
+void PathTraceWorkCPU::copy_to_display(PathTraceDisplay *display,
+ PassMode pass_mode,
+ int num_samples)
{
- half4 *rgba_half = gpu_display->map_texture_buffer();
+ half4 *rgba_half = display->map_texture_buffer();
if (!rgba_half) {
- /* TODO(sergey): Look into using copy_to_gpu_display() if mapping failed. Might be needed for
- * some implementations of GPUDisplay which can not map memory? */
+ /* TODO(sergey): Look into using copy_to_display() if mapping failed. Might be needed for
+ * some implementations of PathTraceDisplay which can not map memory? */
return;
}
@@ -172,7 +183,7 @@ void PathTraceWorkCPU::copy_to_gpu_display(GPUDisplay *gpu_display,
const PassAccessorCPU pass_accessor(pass_access_info, kfilm.exposure, num_samples);
- PassAccessor::Destination destination = get_gpu_display_destination_template(gpu_display);
+ PassAccessor::Destination destination = get_display_destination_template(display);
destination.pixels_half_rgba = rgba_half;
tbb::task_arena local_arena = local_tbb_arena_create(device_);
@@ -180,10 +191,10 @@ void PathTraceWorkCPU::copy_to_gpu_display(GPUDisplay *gpu_display,
pass_accessor.get_render_tile_pixels(buffers_.get(), effective_buffer_params_, destination);
});
- gpu_display->unmap_texture_buffer();
+ display->unmap_texture_buffer();
}
-void PathTraceWorkCPU::destroy_gpu_resources(GPUDisplay * /*gpu_display*/)
+void PathTraceWorkCPU::destroy_gpu_resources(PathTraceDisplay * /*display*/)
{
}
diff --git a/intern/cycles/integrator/path_trace_work_cpu.h b/intern/cycles/integrator/path_trace_work_cpu.h
index ab729bbf879..63ab686588c 100644
--- a/intern/cycles/integrator/path_trace_work_cpu.h
+++ b/intern/cycles/integrator/path_trace_work_cpu.h
@@ -16,19 +16,19 @@
#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
struct KernelWorkTile;
-struct KernelGlobals;
+struct KernelGlobalsCPU;
class CPUKernels;
@@ -48,12 +48,13 @@ class PathTraceWorkCPU : public PathTraceWork {
virtual void render_samples(RenderStatistics &statistics,
int start_sample,
- int samples_num) override;
+ int samples_num,
+ int sample_offset) override;
- virtual void copy_to_gpu_display(GPUDisplay *gpu_display,
- PassMode pass_mode,
- int num_samples) override;
- virtual void destroy_gpu_resources(GPUDisplay *gpu_display) override;
+ virtual void copy_to_display(PathTraceDisplay *display,
+ PassMode pass_mode,
+ int num_samples) override;
+ virtual void destroy_gpu_resources(PathTraceDisplay *display) override;
virtual bool copy_render_buffers_from_device() override;
virtual bool copy_render_buffers_to_device() override;
@@ -64,7 +65,7 @@ class PathTraceWorkCPU : public PathTraceWork {
protected:
/* Core path tracing routine. Renders given work time on the given queue. */
- void render_samples_full_pipeline(KernelGlobals *kernel_globals,
+ void render_samples_full_pipeline(KernelGlobalsCPU *kernel_globals,
const KernelWorkTile &work_tile,
const int samples_num);
diff --git a/intern/cycles/integrator/path_trace_work_gpu.cpp b/intern/cycles/integrator/path_trace_work_gpu.cpp
index 450e8aaac04..7a13447f2cf 100644
--- a/intern/cycles/integrator/path_trace_work_gpu.cpp
+++ b/intern/cycles/integrator/path_trace_work_gpu.cpp
@@ -15,21 +15,58 @@
*/
#include "integrator/path_trace_work_gpu.h"
+#include "integrator/path_trace_display.h"
#include "device/device.h"
#include "integrator/pass_accessor_gpu.h"
-#include "render/buffers.h"
-#include "render/gpu_display.h"
-#include "render/scene.h"
-#include "util/util_logging.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
+static size_t estimate_single_state_size()
+{
+ size_t state_size = 0;
+
+#define KERNEL_STRUCT_BEGIN(name) for (int array_index = 0;; array_index++) {
+#define KERNEL_STRUCT_MEMBER(parent_struct, type, name, feature) state_size += sizeof(type);
+#define KERNEL_STRUCT_ARRAY_MEMBER(parent_struct, type, name, feature) state_size += sizeof(type);
+#define KERNEL_STRUCT_END(name) \
+ break; \
+ }
+#define KERNEL_STRUCT_END_ARRAY(name, cpu_array_size, gpu_array_size) \
+ if (array_index >= gpu_array_size - 1) { \
+ break; \
+ } \
+ }
+/* TODO(sergey): Look into better estimation for fields which depend on scene features. Maybe
+ * maximum state calculation should happen as `alloc_work_memory()`, so that we can react to an
+ * updated scene state here.
+ * For until then use common value. Currently this size is only used for logging, but is weak to
+ * rely on this. */
+#define KERNEL_STRUCT_VOLUME_STACK_SIZE 4
+
+#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
+
+ return state_size;
+}
+
PathTraceWorkGPU::PathTraceWorkGPU(Device *device,
Film *film,
DeviceScene *device_scene,
@@ -41,22 +78,25 @@ PathTraceWorkGPU::PathTraceWorkGPU(Device *device,
integrator_shader_sort_counter_(device, "integrator_shader_sort_counter", MEM_READ_WRITE),
integrator_shader_raytrace_sort_counter_(
device, "integrator_shader_raytrace_sort_counter", MEM_READ_WRITE),
- integrator_next_shadow_catcher_path_index_(
- device, "integrator_next_shadow_catcher_path_index", MEM_READ_WRITE),
+ integrator_shader_sort_prefix_sum_(
+ device, "integrator_shader_sort_prefix_sum", MEM_READ_WRITE),
+ integrator_next_main_path_index_(device, "integrator_next_main_path_index", MEM_READ_WRITE),
+ integrator_next_shadow_path_index_(
+ device, "integrator_next_shadow_path_index", MEM_READ_WRITE),
queued_paths_(device, "queued_paths", MEM_READ_WRITE),
num_queued_paths_(device, "num_queued_paths", MEM_READ_WRITE),
work_tiles_(device, "work_tiles", MEM_READ_WRITE),
- gpu_display_rgba_half_(device, "display buffer half", MEM_READ_WRITE),
- max_num_paths_(queue_->num_concurrent_states(sizeof(IntegratorStateCPU))),
- min_num_active_paths_(queue_->num_concurrent_busy_states()),
- max_active_path_index_(0)
+ display_rgba_half_(device, "display buffer half", MEM_READ_WRITE),
+ max_num_paths_(queue_->num_concurrent_states(estimate_single_state_size())),
+ min_num_active_main_paths_(queue_->num_concurrent_busy_states()),
+ max_active_main_path_index_(0)
{
memset(&integrator_state_gpu_, 0, sizeof(integrator_state_gpu_));
/* Limit number of active paths to the half of the overall state. This is due to the logic in the
* path compaction which relies on the fact that regeneration does not happen sooner than half of
* the states are available again. */
- min_num_active_paths_ = min(min_num_active_paths_, max_num_paths_ / 2);
+ min_num_active_main_paths_ = min(min_num_active_main_paths_, max_num_paths_ / 2);
}
void PathTraceWorkGPU::alloc_integrator_soa()
@@ -64,11 +104,15 @@ void PathTraceWorkGPU::alloc_integrator_soa()
/* IntegrateState allocated as structure of arrays. */
/* Check if we already allocated memory for the required features. */
+ const int requested_volume_stack_size = device_scene_->data.volume_stack_size;
const uint kernel_features = device_scene_->data.kernel_features;
- if ((integrator_state_soa_kernel_features_ & kernel_features) == kernel_features) {
+ if ((integrator_state_soa_kernel_features_ & kernel_features) == kernel_features &&
+ integrator_state_soa_volume_stack_size_ >= requested_volume_stack_size) {
return;
}
integrator_state_soa_kernel_features_ = kernel_features;
+ integrator_state_soa_volume_stack_size_ = max(integrator_state_soa_volume_stack_size_,
+ requested_volume_stack_size);
/* Allocate a device only memory buffer before for each struct member, and then
* write the pointers into a struct that resides in constant memory.
@@ -76,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_); \
@@ -84,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); \
@@ -95,17 +139,32 @@ void PathTraceWorkGPU::alloc_integrator_soa()
#define KERNEL_STRUCT_END(name) \
break; \
}
-#define KERNEL_STRUCT_END_ARRAY(name, array_size) \
- if (array_index == array_size - 1) { \
+#define KERNEL_STRUCT_END_ARRAY(name, cpu_array_size, gpu_array_size) \
+ if (array_index >= gpu_array_size - 1) { \
break; \
} \
}
-#include "kernel/integrator/integrator_state_template.h"
+#define KERNEL_STRUCT_VOLUME_STACK_SIZE (integrator_state_soa_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
+
+ if (VLOG_IS_ON(3)) {
+ size_t total_soa_size = 0;
+ for (auto &&soa_memory : integrator_state_soa_) {
+ total_soa_size += soa_memory->memory_size();
+ }
+
+ VLOG(3) << "GPU SoA state size: " << string_human_readable_size(total_soa_size);
+ }
}
void PathTraceWorkGPU::alloc_integrator_queue()
@@ -142,6 +201,9 @@ void PathTraceWorkGPU::alloc_integrator_sorting()
integrator_shader_raytrace_sort_counter_.alloc(max_shaders);
integrator_shader_raytrace_sort_counter_.zero_to_device();
+ integrator_shader_sort_prefix_sum_.alloc(max_shaders);
+ integrator_shader_sort_prefix_sum_.zero_to_device();
+
integrator_state_gpu_.sort_key_counter[DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE] =
(int *)integrator_shader_sort_counter_.device_pointer;
integrator_state_gpu_.sort_key_counter[DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE] =
@@ -151,16 +213,22 @@ void PathTraceWorkGPU::alloc_integrator_sorting()
void PathTraceWorkGPU::alloc_integrator_path_split()
{
- if (integrator_next_shadow_catcher_path_index_.size() != 0) {
- return;
+ if (integrator_next_shadow_path_index_.size() == 0) {
+ integrator_next_shadow_path_index_.alloc(1);
+ integrator_next_shadow_path_index_.zero_to_device();
+
+ integrator_state_gpu_.next_shadow_path_index =
+ (int *)integrator_next_shadow_path_index_.device_pointer;
}
- integrator_next_shadow_catcher_path_index_.alloc(1);
- /* TODO(sergey): Use queue? */
- integrator_next_shadow_catcher_path_index_.zero_to_device();
+ if (integrator_next_main_path_index_.size() == 0) {
+ integrator_next_main_path_index_.alloc(1);
+ integrator_next_shadow_path_index_.data()[0] = 0;
+ integrator_next_main_path_index_.zero_to_device();
- integrator_state_gpu_.next_shadow_catcher_path_index =
- (int *)integrator_next_shadow_catcher_path_index_.device_pointer;
+ integrator_state_gpu_.next_main_path_index =
+ (int *)integrator_next_main_path_index_.device_pointer;
+ }
}
void PathTraceWorkGPU::alloc_work_memory()
@@ -182,15 +250,21 @@ void PathTraceWorkGPU::init_execution()
void PathTraceWorkGPU::render_samples(RenderStatistics &statistics,
int start_sample,
- int samples_num)
+ int samples_num,
+ int sample_offset)
{
/* Limit number of states for the tile and rely on a greedy scheduling of tiles. This allows to
* add more work (because tiles are smaller, so there is higher chance that more paths will
* become busy after adding new tiles). This is especially important for the shadow catcher which
* 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_.set_accelerated_rt((device_->get_bvh_layout_mask() & BVH_LAYOUT_OPTIX) !=
+ 0);
+ work_tile_scheduler_.reset(effective_buffer_params_,
+ start_sample,
+ samples_num,
+ sample_offset,
+ device_scene_->data.integrator.scrambling_distance);
enqueue_reset();
@@ -234,7 +308,7 @@ void PathTraceWorkGPU::render_samples(RenderStatistics &statistics,
break;
}
- num_busy_accum += get_num_active_paths();
+ num_busy_accum += num_active_main_paths_paths();
++num_iterations;
}
@@ -260,7 +334,8 @@ DeviceKernel PathTraceWorkGPU::get_most_queued_kernel() const
void PathTraceWorkGPU::enqueue_reset()
{
- void *args[] = {&max_num_paths_};
+ DeviceKernelArguments args(&max_num_paths_);
+
queue_->enqueue(DEVICE_KERNEL_INTEGRATOR_RESET, max_num_paths_, args);
queue_->zero_to_device(integrator_queue_counter_);
queue_->zero_to_device(integrator_shader_sort_counter_);
@@ -293,50 +368,65 @@ bool PathTraceWorkGPU::enqueue_path_iteration()
return false;
}
- /* Finish shadows before potentially adding more shadow rays. We can only
- * store one shadow ray in the integrator state. */
- if (kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE ||
- kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE ||
- kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME) {
- if (queue_counter->num_queued[DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW]) {
- enqueue_path_iteration(DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW);
- return true;
+ /* For kernels that add shadow paths, check if there is enough space available.
+ * If not, schedule shadow kernels first to clear out the shadow paths. */
+ int num_paths_limit = INT_MAX;
+
+ if (kernel_creates_shadow_paths(kernel)) {
+ compact_shadow_paths();
+
+ const int available_shadow_paths = max_num_paths_ -
+ integrator_next_shadow_path_index_.data()[0];
+ if (available_shadow_paths < queue_counter->num_queued[kernel]) {
+ if (queue_counter->num_queued[DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW]) {
+ enqueue_path_iteration(DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW);
+ return true;
+ }
+ else if (queue_counter->num_queued[DEVICE_KERNEL_INTEGRATOR_SHADE_SHADOW]) {
+ enqueue_path_iteration(DEVICE_KERNEL_INTEGRATOR_SHADE_SHADOW);
+ return true;
+ }
}
- else if (queue_counter->num_queued[DEVICE_KERNEL_INTEGRATOR_SHADE_SHADOW]) {
- enqueue_path_iteration(DEVICE_KERNEL_INTEGRATOR_SHADE_SHADOW);
- return true;
+ else if (kernel_creates_ao_paths(kernel)) {
+ /* AO kernel creates two shadow paths, so limit number of states to schedule. */
+ num_paths_limit = available_shadow_paths / 2;
}
}
/* Schedule kernel with maximum number of queued items. */
- enqueue_path_iteration(kernel);
+ enqueue_path_iteration(kernel, num_paths_limit);
+
+ /* Update next shadow path index for kernels that can add shadow paths. */
+ if (kernel_creates_shadow_paths(kernel)) {
+ queue_->copy_from_device(integrator_next_shadow_path_index_);
+ }
+
return true;
}
-void PathTraceWorkGPU::enqueue_path_iteration(DeviceKernel kernel)
+void PathTraceWorkGPU::enqueue_path_iteration(DeviceKernel kernel, const int num_paths_limit)
{
- void *d_path_index = (void *)NULL;
+ device_ptr d_path_index = 0;
/* Create array of path indices for which this kernel is queued to be executed. */
- int work_size = max_active_path_index_;
+ int work_size = kernel_max_active_main_path_index(kernel);
IntegratorQueueCounter *queue_counter = integrator_queue_counter_.data();
int num_queued = queue_counter->num_queued[kernel];
- if (kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE ||
- kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE) {
+ if (kernel_uses_sorting(kernel)) {
/* Compute array of active paths, sorted by shader. */
work_size = num_queued;
- d_path_index = (void *)queued_paths_.device_pointer;
+ d_path_index = queued_paths_.device_pointer;
- compute_sorted_queued_paths(DEVICE_KERNEL_INTEGRATOR_SORTED_PATHS_ARRAY, kernel);
+ compute_sorted_queued_paths(
+ DEVICE_KERNEL_INTEGRATOR_SORTED_PATHS_ARRAY, kernel, num_paths_limit);
}
else if (num_queued < work_size) {
work_size = num_queued;
- d_path_index = (void *)queued_paths_.device_pointer;
+ d_path_index = queued_paths_.device_pointer;
- if (kernel == DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW ||
- kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_SHADOW) {
+ if (kernel_is_shadow_path(kernel)) {
/* Compute array of active shadow paths for specific kernel. */
compute_queued_paths(DEVICE_KERNEL_INTEGRATOR_QUEUED_SHADOW_PATHS_ARRAY, kernel);
}
@@ -346,15 +436,24 @@ void PathTraceWorkGPU::enqueue_path_iteration(DeviceKernel kernel)
}
}
+ work_size = min(work_size, num_paths_limit);
+
DCHECK_LE(work_size, max_num_paths_);
switch (kernel) {
- case DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST:
+ case DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST: {
+ /* Closest ray intersection kernels with integrator state and render buffer. */
+ DeviceKernelArguments args(&d_path_index, &buffers_->buffer.device_pointer, &work_size);
+
+ queue_->enqueue(kernel, work_size, args);
+ break;
+ }
+
case DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW:
case DEVICE_KERNEL_INTEGRATOR_INTERSECT_SUBSURFACE:
case DEVICE_KERNEL_INTEGRATOR_INTERSECT_VOLUME_STACK: {
/* Ray intersection kernels with integrator state. */
- void *args[] = {&d_path_index, const_cast<int *>(&work_size)};
+ DeviceKernelArguments args(&d_path_index, &work_size);
queue_->enqueue(kernel, work_size, args);
break;
@@ -366,8 +465,7 @@ void PathTraceWorkGPU::enqueue_path_iteration(DeviceKernel kernel)
case DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE:
case DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME: {
/* Shading kernels with integrator state and render buffer. */
- void *d_render_buffer = (void *)buffers_->buffer.device_pointer;
- void *args[] = {&d_path_index, &d_render_buffer, const_cast<int *>(&work_size)};
+ DeviceKernelArguments args(&d_path_index, &buffers_->buffer.device_pointer, &work_size);
queue_->enqueue(kernel, work_size, args);
break;
@@ -380,17 +478,22 @@ void PathTraceWorkGPU::enqueue_path_iteration(DeviceKernel kernel)
}
}
-void PathTraceWorkGPU::compute_sorted_queued_paths(DeviceKernel kernel, DeviceKernel queued_kernel)
+void PathTraceWorkGPU::compute_sorted_queued_paths(DeviceKernel kernel,
+ DeviceKernel queued_kernel,
+ const int num_paths_limit)
{
int d_queued_kernel = queued_kernel;
- void *d_counter = integrator_state_gpu_.sort_key_counter[d_queued_kernel];
- assert(d_counter != nullptr);
+ device_ptr d_counter = (device_ptr)integrator_state_gpu_.sort_key_counter[d_queued_kernel];
+ device_ptr d_prefix_sum = integrator_shader_sort_prefix_sum_.device_pointer;
+ assert(d_counter != 0 && d_prefix_sum != 0);
/* Compute prefix sum of number of active paths with each shader. */
{
const int work_size = 1;
int max_shaders = device_scene_->data.max_shaders;
- void *args[] = {&d_counter, &max_shaders};
+
+ DeviceKernelArguments args(&d_counter, &d_prefix_sum, &max_shaders);
+
queue_->enqueue(DEVICE_KERNEL_PREFIX_SUM, work_size, args);
}
@@ -399,28 +502,24 @@ void PathTraceWorkGPU::compute_sorted_queued_paths(DeviceKernel kernel, DeviceKe
/* Launch kernel to fill the active paths arrays. */
{
/* TODO: this could be smaller for terminated paths based on amount of work we want
- * to schedule. */
- const int work_size = max_active_path_index_;
+ * to schedule, and also based on num_paths_limit.
+ *
+ * Also, when the number paths is limited it may be better to prefer paths from the
+ * end of the array since compaction would need to do less work. */
+ const int work_size = kernel_max_active_main_path_index(queued_kernel);
- void *d_queued_paths = (void *)queued_paths_.device_pointer;
- void *d_num_queued_paths = (void *)num_queued_paths_.device_pointer;
- void *args[] = {const_cast<int *>(&work_size),
- &d_queued_paths,
- &d_num_queued_paths,
- &d_counter,
- &d_queued_kernel};
+ device_ptr d_queued_paths = queued_paths_.device_pointer;
+ device_ptr d_num_queued_paths = num_queued_paths_.device_pointer;
- queue_->enqueue(kernel, work_size, args);
- }
+ DeviceKernelArguments args(&work_size,
+ &num_paths_limit,
+ &d_queued_paths,
+ &d_num_queued_paths,
+ &d_counter,
+ &d_prefix_sum,
+ &d_queued_kernel);
- if (queued_kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE) {
- queue_->zero_to_device(integrator_shader_sort_counter_);
- }
- else if (queued_kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE) {
- queue_->zero_to_device(integrator_shader_raytrace_sort_counter_);
- }
- else {
- assert(0);
+ queue_->enqueue(kernel, work_size, args);
}
}
@@ -429,49 +528,111 @@ void PathTraceWorkGPU::compute_queued_paths(DeviceKernel kernel, DeviceKernel qu
int d_queued_kernel = queued_kernel;
/* Launch kernel to fill the active paths arrays. */
- const int work_size = max_active_path_index_;
- void *d_queued_paths = (void *)queued_paths_.device_pointer;
- void *d_num_queued_paths = (void *)num_queued_paths_.device_pointer;
- void *args[] = {
- const_cast<int *>(&work_size), &d_queued_paths, &d_num_queued_paths, &d_queued_kernel};
+ const int work_size = kernel_max_active_main_path_index(queued_kernel);
+ device_ptr d_queued_paths = queued_paths_.device_pointer;
+ device_ptr d_num_queued_paths = num_queued_paths_.device_pointer;
+
+ DeviceKernelArguments args(&work_size, &d_queued_paths, &d_num_queued_paths, &d_queued_kernel);
queue_->zero_to_device(num_queued_paths_);
queue_->enqueue(kernel, work_size, args);
}
-void PathTraceWorkGPU::compact_states(const int num_active_paths)
+void PathTraceWorkGPU::compact_main_paths(const int num_active_paths)
{
+ /* Early out if there is nothing that needs to be compacted. */
if (num_active_paths == 0) {
- max_active_path_index_ = 0;
+ max_active_main_path_index_ = 0;
+ return;
}
- /* Compact fragmented path states into the start of the array, moving any paths
- * with index higher than the number of active paths into the gaps. */
- if (max_active_path_index_ == num_active_paths) {
+ const int min_compact_paths = 32;
+ if (max_active_main_path_index_ == num_active_paths ||
+ max_active_main_path_index_ < min_compact_paths) {
return;
}
- void *d_compact_paths = (void *)queued_paths_.device_pointer;
- void *d_num_queued_paths = (void *)num_queued_paths_.device_pointer;
+ /* Compact. */
+ compact_paths(num_active_paths,
+ max_active_main_path_index_,
+ DEVICE_KERNEL_INTEGRATOR_TERMINATED_PATHS_ARRAY,
+ DEVICE_KERNEL_INTEGRATOR_COMPACT_PATHS_ARRAY,
+ DEVICE_KERNEL_INTEGRATOR_COMPACT_STATES);
+
+ /* Adjust max active path index now we know which part of the array is actually used. */
+ max_active_main_path_index_ = num_active_paths;
+}
+
+void PathTraceWorkGPU::compact_shadow_paths()
+{
+ IntegratorQueueCounter *queue_counter = integrator_queue_counter_.data();
+ const int num_active_paths =
+ queue_counter->num_queued[DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW] +
+ queue_counter->num_queued[DEVICE_KERNEL_INTEGRATOR_SHADE_SHADOW];
+
+ /* Early out if there is nothing that needs to be compacted. */
+ if (num_active_paths == 0) {
+ if (integrator_next_shadow_path_index_.data()[0] != 0) {
+ integrator_next_shadow_path_index_.data()[0] = 0;
+ queue_->copy_to_device(integrator_next_shadow_path_index_);
+ }
+ return;
+ }
+
+ /* Compact if we can reduce the space used by half. Not always since
+ * compaction has a cost. */
+ const float shadow_compact_ratio = 0.5f;
+ const int min_compact_paths = 32;
+ if (integrator_next_shadow_path_index_.data()[0] < num_active_paths * shadow_compact_ratio ||
+ integrator_next_shadow_path_index_.data()[0] < min_compact_paths) {
+ return;
+ }
+
+ /* Compact. */
+ compact_paths(num_active_paths,
+ integrator_next_shadow_path_index_.data()[0],
+ DEVICE_KERNEL_INTEGRATOR_TERMINATED_SHADOW_PATHS_ARRAY,
+ DEVICE_KERNEL_INTEGRATOR_COMPACT_SHADOW_PATHS_ARRAY,
+ DEVICE_KERNEL_INTEGRATOR_COMPACT_SHADOW_STATES);
+
+ /* Adjust max active path index now we know which part of the array is actually used. */
+ integrator_next_shadow_path_index_.data()[0] = num_active_paths;
+ queue_->copy_to_device(integrator_next_shadow_path_index_);
+}
+
+void PathTraceWorkGPU::compact_paths(const int num_active_paths,
+ const int max_active_path_index,
+ DeviceKernel terminated_paths_kernel,
+ DeviceKernel compact_paths_kernel,
+ DeviceKernel compact_kernel)
+{
+ /* Compact fragmented path states into the start of the array, moving any paths
+ * with index higher than the number of active paths into the gaps. */
+ device_ptr d_compact_paths = queued_paths_.device_pointer;
+ device_ptr d_num_queued_paths = num_queued_paths_.device_pointer;
/* Create array with terminated paths that we can write to. */
{
/* TODO: can the work size be reduced here? */
int offset = num_active_paths;
int work_size = num_active_paths;
- void *args[] = {&work_size, &d_compact_paths, &d_num_queued_paths, &offset};
+
+ DeviceKernelArguments args(&work_size, &d_compact_paths, &d_num_queued_paths, &offset);
+
queue_->zero_to_device(num_queued_paths_);
- queue_->enqueue(DEVICE_KERNEL_INTEGRATOR_TERMINATED_PATHS_ARRAY, work_size, args);
+ queue_->enqueue(terminated_paths_kernel, work_size, args);
}
/* Create array of paths that we need to compact, where the path index is bigger
* than the number of active paths. */
{
- int work_size = max_active_path_index_;
- void *args[] = {
- &work_size, &d_compact_paths, &d_num_queued_paths, const_cast<int *>(&num_active_paths)};
+ int work_size = max_active_path_index;
+
+ DeviceKernelArguments args(
+ &work_size, &d_compact_paths, &d_num_queued_paths, &num_active_paths);
+
queue_->zero_to_device(num_queued_paths_);
- queue_->enqueue(DEVICE_KERNEL_INTEGRATOR_COMPACT_PATHS_ARRAY, work_size, args);
+ queue_->enqueue(compact_paths_kernel, work_size, args);
}
queue_->copy_from_device(num_queued_paths_);
@@ -484,15 +645,12 @@ void PathTraceWorkGPU::compact_states(const int num_active_paths)
int work_size = num_compact_paths;
int active_states_offset = 0;
int terminated_states_offset = num_active_paths;
- void *args[] = {
- &d_compact_paths, &active_states_offset, &terminated_states_offset, &work_size};
- queue_->enqueue(DEVICE_KERNEL_INTEGRATOR_COMPACT_STATES, work_size, args);
- }
- queue_->synchronize();
+ DeviceKernelArguments args(
+ &d_compact_paths, &active_states_offset, &terminated_states_offset, &work_size);
- /* Adjust max active path index now we know which part of the array is actually used. */
- max_active_path_index_ = num_active_paths;
+ queue_->enqueue(compact_kernel, work_size, args);
+ }
}
bool PathTraceWorkGPU::enqueue_work_tiles(bool &finished)
@@ -506,7 +664,7 @@ bool PathTraceWorkGPU::enqueue_work_tiles(bool &finished)
return false;
}
- int num_active_paths = get_num_active_paths();
+ int num_active_paths = num_active_main_paths_paths();
/* Don't schedule more work if canceling. */
if (is_cancel_requested()) {
@@ -546,7 +704,7 @@ bool PathTraceWorkGPU::enqueue_work_tiles(bool &finished)
/* Schedule when we're out of paths or there are too few paths to keep the
* device occupied. */
int num_paths = num_active_paths;
- if (num_paths == 0 || num_paths < min_num_active_paths_) {
+ if (num_paths == 0 || num_paths < min_num_active_main_paths_) {
/* Get work tiles until the maximum number of path is reached. */
while (num_paths < max_num_camera_paths) {
KernelWorkTile work_tile;
@@ -573,11 +731,11 @@ bool PathTraceWorkGPU::enqueue_work_tiles(bool &finished)
/* Compact state array when number of paths becomes small relative to the
* known maximum path index, which makes computing active index arrays slow. */
- compact_states(num_active_paths);
+ compact_main_paths(num_active_paths);
if (has_shadow_catcher()) {
- integrator_next_shadow_catcher_path_index_.data()[0] = num_paths;
- queue_->copy_to_device(integrator_next_shadow_catcher_path_index_);
+ integrator_next_main_path_index_.data()[0] = num_paths;
+ queue_->copy_to_device(integrator_next_main_path_index_);
}
enqueue_work_tiles((device_scene_->data.bake.use) ? DEVICE_KERNEL_INTEGRATOR_INIT_FROM_BAKE :
@@ -619,23 +777,20 @@ void PathTraceWorkGPU::enqueue_work_tiles(DeviceKernel kernel,
queue_->copy_to_device(work_tiles_);
- void *d_work_tiles = (void *)work_tiles_.device_pointer;
- void *d_render_buffer = (void *)buffers_->buffer.device_pointer;
+ device_ptr d_work_tiles = work_tiles_.device_pointer;
+ device_ptr d_render_buffer = buffers_->buffer.device_pointer;
/* Launch kernel. */
- void *args[] = {&d_work_tiles,
- const_cast<int *>(&num_work_tiles),
- &d_render_buffer,
- const_cast<int *>(&max_tile_work_size)};
+ DeviceKernelArguments args(
+ &d_work_tiles, &num_work_tiles, &d_render_buffer, &max_tile_work_size);
queue_->enqueue(kernel, max_tile_work_size * num_work_tiles, args);
- max_active_path_index_ = path_index_offset + num_predicted_splits;
+ max_active_main_path_index_ = path_index_offset + num_predicted_splits;
}
-int PathTraceWorkGPU::get_num_active_paths()
+int PathTraceWorkGPU::num_active_main_paths_paths()
{
- /* TODO: this is wrong, does not account for duplicates with shadow! */
IntegratorQueueCounter *queue_counter = integrator_queue_counter_.data();
int num_paths = 0;
@@ -643,7 +798,10 @@ int PathTraceWorkGPU::get_num_active_paths()
DCHECK_GE(queue_counter->num_queued[i], 0)
<< "Invalid number of queued states for kernel "
<< device_kernel_as_string(static_cast<DeviceKernel>(i));
- num_paths += queue_counter->num_queued[i];
+
+ if (!kernel_is_shadow_path((DeviceKernel)i)) {
+ num_paths += queue_counter->num_queued[i];
+ }
}
return num_paths;
@@ -652,7 +810,7 @@ int PathTraceWorkGPU::get_num_active_paths()
bool PathTraceWorkGPU::should_use_graphics_interop()
{
/* There are few aspects with the graphics interop when using multiple devices caused by the fact
- * that the GPUDisplay has a single texture:
+ * that the PathTraceDisplay has a single texture:
*
* CUDA will return `CUDA_ERROR_NOT_SUPPORTED` from `cuGraphicsGLRegisterBuffer()` when
* attempting to register OpenGL PBO which has been mapped. Which makes sense, because
@@ -666,10 +824,10 @@ bool PathTraceWorkGPU::should_use_graphics_interop()
interop_use_ = device->should_use_graphics_interop();
if (interop_use_) {
- VLOG(2) << "Will be using graphics interop GPU display update.";
+ VLOG(2) << "Using graphics interop GPU display update.";
}
else {
- VLOG(2) << "Will be using naive GPU display update.";
+ VLOG(2) << "Using naive GPU display update.";
}
interop_use_checked_ = true;
@@ -678,9 +836,9 @@ bool PathTraceWorkGPU::should_use_graphics_interop()
return interop_use_;
}
-void PathTraceWorkGPU::copy_to_gpu_display(GPUDisplay *gpu_display,
- PassMode pass_mode,
- int num_samples)
+void PathTraceWorkGPU::copy_to_display(PathTraceDisplay *display,
+ PassMode pass_mode,
+ int num_samples)
{
if (device_->have_error()) {
/* Don't attempt to update GPU display if the device has errors: the error state will make
@@ -694,7 +852,7 @@ void PathTraceWorkGPU::copy_to_gpu_display(GPUDisplay *gpu_display,
}
if (should_use_graphics_interop()) {
- if (copy_to_gpu_display_interop(gpu_display, pass_mode, num_samples)) {
+ if (copy_to_display_interop(display, pass_mode, num_samples)) {
return;
}
@@ -703,66 +861,66 @@ void PathTraceWorkGPU::copy_to_gpu_display(GPUDisplay *gpu_display,
interop_use_ = false;
}
- copy_to_gpu_display_naive(gpu_display, pass_mode, num_samples);
+ copy_to_display_naive(display, pass_mode, num_samples);
}
-void PathTraceWorkGPU::copy_to_gpu_display_naive(GPUDisplay *gpu_display,
- PassMode pass_mode,
- int num_samples)
+void PathTraceWorkGPU::copy_to_display_naive(PathTraceDisplay *display,
+ PassMode pass_mode,
+ int num_samples)
{
const int full_x = effective_buffer_params_.full_x;
const int full_y = effective_buffer_params_.full_y;
- const int width = effective_buffer_params_.width;
- const int height = effective_buffer_params_.height;
- const int final_width = buffers_->params.width;
- const int final_height = buffers_->params.height;
+ const int width = effective_buffer_params_.window_width;
+ const int height = effective_buffer_params_.window_height;
+ const int final_width = buffers_->params.window_width;
+ const int final_height = buffers_->params.window_height;
- const int texture_x = full_x - effective_full_params_.full_x;
- const int texture_y = full_y - effective_full_params_.full_y;
+ const int texture_x = full_x - effective_big_tile_params_.full_x +
+ effective_buffer_params_.window_x - effective_big_tile_params_.window_x;
+ const int texture_y = full_y - effective_big_tile_params_.full_y +
+ effective_buffer_params_.window_y - effective_big_tile_params_.window_y;
/* Re-allocate display memory if needed, and make sure the device pointer is allocated.
*
* NOTE: allocation happens to the final resolution so that no re-allocation happens on every
* change of the resolution divider. However, if the display becomes smaller, shrink the
* allocated memory as well. */
- if (gpu_display_rgba_half_.data_width != final_width ||
- gpu_display_rgba_half_.data_height != final_height) {
- gpu_display_rgba_half_.alloc(final_width, final_height);
+ if (display_rgba_half_.data_width != final_width ||
+ display_rgba_half_.data_height != final_height) {
+ display_rgba_half_.alloc(final_width, final_height);
/* TODO(sergey): There should be a way to make sure device-side memory is allocated without
* transferring zeroes to the device. */
- queue_->zero_to_device(gpu_display_rgba_half_);
+ queue_->zero_to_device(display_rgba_half_);
}
PassAccessor::Destination destination(film_->get_display_pass());
- destination.d_pixels_half_rgba = gpu_display_rgba_half_.device_pointer;
+ destination.d_pixels_half_rgba = display_rgba_half_.device_pointer;
get_render_tile_film_pixels(destination, pass_mode, num_samples);
- queue_->copy_from_device(gpu_display_rgba_half_);
+ queue_->copy_from_device(display_rgba_half_);
queue_->synchronize();
- gpu_display->copy_pixels_to_texture(
- gpu_display_rgba_half_.data(), texture_x, texture_y, width, height);
+ display->copy_pixels_to_texture(display_rgba_half_.data(), texture_x, texture_y, width, height);
}
-bool PathTraceWorkGPU::copy_to_gpu_display_interop(GPUDisplay *gpu_display,
- PassMode pass_mode,
- int num_samples)
+bool PathTraceWorkGPU::copy_to_display_interop(PathTraceDisplay *display,
+ PassMode pass_mode,
+ int num_samples)
{
if (!device_graphics_interop_) {
device_graphics_interop_ = queue_->graphics_interop_create();
}
- const DeviceGraphicsInteropDestination graphics_interop_dst =
- gpu_display->graphics_interop_get();
- device_graphics_interop_->set_destination(graphics_interop_dst);
+ const DisplayDriver::GraphicsInterop graphics_interop_dst = display->graphics_interop_get();
+ device_graphics_interop_->set_display_interop(graphics_interop_dst);
const device_ptr d_rgba_half = device_graphics_interop_->map();
if (!d_rgba_half) {
return false;
}
- PassAccessor::Destination destination = get_gpu_display_destination_template(gpu_display);
+ PassAccessor::Destination destination = get_display_destination_template(display);
destination.d_pixels_half_rgba = d_rgba_half;
get_render_tile_film_pixels(destination, pass_mode, num_samples);
@@ -772,14 +930,14 @@ bool PathTraceWorkGPU::copy_to_gpu_display_interop(GPUDisplay *gpu_display,
return true;
}
-void PathTraceWorkGPU::destroy_gpu_resources(GPUDisplay *gpu_display)
+void PathTraceWorkGPU::destroy_gpu_resources(PathTraceDisplay *display)
{
if (!device_graphics_interop_) {
return;
}
- gpu_display->graphics_interop_activate();
+ display->graphics_interop_activate();
device_graphics_interop_ = nullptr;
- gpu_display->graphics_interop_deactivate();
+ display->graphics_interop_deactivate();
}
void PathTraceWorkGPU::get_render_tile_film_pixels(const PassAccessor::Destination &destination,
@@ -816,16 +974,16 @@ int PathTraceWorkGPU::adaptive_sampling_convergence_check_count_active(float thr
const int work_size = effective_buffer_params_.width * effective_buffer_params_.height;
- void *args[] = {&buffers_->buffer.device_pointer,
- const_cast<int *>(&effective_buffer_params_.full_x),
- const_cast<int *>(&effective_buffer_params_.full_y),
- const_cast<int *>(&effective_buffer_params_.width),
- const_cast<int *>(&effective_buffer_params_.height),
- &threshold,
- &reset,
- &effective_buffer_params_.offset,
- &effective_buffer_params_.stride,
- &num_active_pixels.device_pointer};
+ DeviceKernelArguments args(&buffers_->buffer.device_pointer,
+ &effective_buffer_params_.full_x,
+ &effective_buffer_params_.full_y,
+ &effective_buffer_params_.width,
+ &effective_buffer_params_.height,
+ &threshold,
+ &reset,
+ &effective_buffer_params_.offset,
+ &effective_buffer_params_.stride,
+ &num_active_pixels.device_pointer);
queue_->enqueue(DEVICE_KERNEL_ADAPTIVE_SAMPLING_CONVERGENCE_CHECK, work_size, args);
@@ -839,13 +997,13 @@ void PathTraceWorkGPU::enqueue_adaptive_sampling_filter_x()
{
const int work_size = effective_buffer_params_.height;
- void *args[] = {&buffers_->buffer.device_pointer,
- &effective_buffer_params_.full_x,
- &effective_buffer_params_.full_y,
- &effective_buffer_params_.width,
- &effective_buffer_params_.height,
- &effective_buffer_params_.offset,
- &effective_buffer_params_.stride};
+ DeviceKernelArguments args(&buffers_->buffer.device_pointer,
+ &effective_buffer_params_.full_x,
+ &effective_buffer_params_.full_y,
+ &effective_buffer_params_.width,
+ &effective_buffer_params_.height,
+ &effective_buffer_params_.offset,
+ &effective_buffer_params_.stride);
queue_->enqueue(DEVICE_KERNEL_ADAPTIVE_SAMPLING_CONVERGENCE_FILTER_X, work_size, args);
}
@@ -854,13 +1012,13 @@ void PathTraceWorkGPU::enqueue_adaptive_sampling_filter_y()
{
const int work_size = effective_buffer_params_.width;
- void *args[] = {&buffers_->buffer.device_pointer,
- &effective_buffer_params_.full_x,
- &effective_buffer_params_.full_y,
- &effective_buffer_params_.width,
- &effective_buffer_params_.height,
- &effective_buffer_params_.offset,
- &effective_buffer_params_.stride};
+ DeviceKernelArguments args(&buffers_->buffer.device_pointer,
+ &effective_buffer_params_.full_x,
+ &effective_buffer_params_.full_y,
+ &effective_buffer_params_.width,
+ &effective_buffer_params_.height,
+ &effective_buffer_params_.offset,
+ &effective_buffer_params_.stride);
queue_->enqueue(DEVICE_KERNEL_ADAPTIVE_SAMPLING_CONVERGENCE_FILTER_Y, work_size, args);
}
@@ -869,10 +1027,10 @@ void PathTraceWorkGPU::cryptomatte_postproces()
{
const int work_size = effective_buffer_params_.width * effective_buffer_params_.height;
- void *args[] = {&buffers_->buffer.device_pointer,
- const_cast<int *>(&work_size),
- &effective_buffer_params_.offset,
- &effective_buffer_params_.stride};
+ DeviceKernelArguments args(&buffers_->buffer.device_pointer,
+ &work_size,
+ &effective_buffer_params_.offset,
+ &effective_buffer_params_.stride);
queue_->enqueue(DEVICE_KERNEL_CRYPTOMATTE_POSTPROCESS, work_size, args);
}
@@ -910,7 +1068,7 @@ bool PathTraceWorkGPU::has_shadow_catcher() const
int PathTraceWorkGPU::shadow_catcher_count_possible_splits()
{
- if (max_active_path_index_ == 0) {
+ if (max_active_main_path_index_ == 0) {
return 0;
}
@@ -920,9 +1078,10 @@ int PathTraceWorkGPU::shadow_catcher_count_possible_splits()
queue_->zero_to_device(num_queued_paths_);
- const int work_size = max_active_path_index_;
- void *d_num_queued_paths = (void *)num_queued_paths_.device_pointer;
- void *args[] = {const_cast<int *>(&work_size), &d_num_queued_paths};
+ const int work_size = max_active_main_path_index_;
+ device_ptr d_num_queued_paths = num_queued_paths_.device_pointer;
+
+ DeviceKernelArguments args(&work_size, &d_num_queued_paths);
queue_->enqueue(DEVICE_KERNEL_INTEGRATOR_SHADOW_CATCHER_COUNT_POSSIBLE_SPLITS, work_size, args);
queue_->copy_from_device(num_queued_paths_);
@@ -931,4 +1090,36 @@ int PathTraceWorkGPU::shadow_catcher_count_possible_splits()
return num_queued_paths_.data()[0];
}
+bool PathTraceWorkGPU::kernel_uses_sorting(DeviceKernel kernel)
+{
+ return (kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE ||
+ kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE);
+}
+
+bool PathTraceWorkGPU::kernel_creates_shadow_paths(DeviceKernel kernel)
+{
+ return (kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE ||
+ kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE ||
+ kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME);
+}
+
+bool PathTraceWorkGPU::kernel_creates_ao_paths(DeviceKernel kernel)
+{
+ return (device_scene_->data.kernel_features & KERNEL_FEATURE_AO) &&
+ (kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE ||
+ kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE);
+}
+
+bool PathTraceWorkGPU::kernel_is_shadow_path(DeviceKernel kernel)
+{
+ return (kernel == DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW ||
+ kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_SHADOW);
+}
+
+int PathTraceWorkGPU::kernel_max_active_main_path_index(DeviceKernel kernel)
+{
+ return (kernel_is_shadow_path(kernel)) ? integrator_next_shadow_path_index_.data()[0] :
+ max_active_main_path_index_;
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/integrator/path_trace_work_gpu.h b/intern/cycles/integrator/path_trace_work_gpu.h
index 38788122b0d..5aa497c26e7 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
@@ -46,12 +46,13 @@ class PathTraceWorkGPU : public PathTraceWork {
virtual void render_samples(RenderStatistics &statistics,
int start_sample,
- int samples_num) override;
+ int samples_num,
+ int sample_offset) override;
- virtual void copy_to_gpu_display(GPUDisplay *gpu_display,
- PassMode pass_mode,
- int num_samples) override;
- virtual void destroy_gpu_resources(GPUDisplay *gpu_display) override;
+ virtual void copy_to_display(PathTraceDisplay *display,
+ PassMode pass_mode,
+ int num_samples) override;
+ virtual void destroy_gpu_resources(PathTraceDisplay *display) override;
virtual bool copy_render_buffers_from_device() override;
virtual bool copy_render_buffers_to_device() override;
@@ -79,25 +80,33 @@ class PathTraceWorkGPU : public PathTraceWork {
const int num_predicted_splits);
bool enqueue_path_iteration();
- void enqueue_path_iteration(DeviceKernel kernel);
+ void enqueue_path_iteration(DeviceKernel kernel, const int num_paths_limit = INT_MAX);
void compute_queued_paths(DeviceKernel kernel, DeviceKernel queued_kernel);
- void compute_sorted_queued_paths(DeviceKernel kernel, DeviceKernel queued_kernel);
+ void compute_sorted_queued_paths(DeviceKernel kernel,
+ DeviceKernel queued_kernel,
+ const int num_paths_limit);
- void compact_states(const int num_active_paths);
+ void compact_main_paths(const int num_active_paths);
+ void compact_shadow_paths();
+ void compact_paths(const int num_active_paths,
+ const int max_active_path_index,
+ DeviceKernel terminated_paths_kernel,
+ DeviceKernel compact_paths_kernel,
+ DeviceKernel compact_kernel);
- int get_num_active_paths();
+ int num_active_main_paths_paths();
- /* Check whether graphics interop can be used for the GPUDisplay update. */
+ /* Check whether graphics interop can be used for the PathTraceDisplay update. */
bool should_use_graphics_interop();
- /* Naive implementation of the `copy_to_gpu_display()` which performs film conversion on the
- * device, then copies pixels to the host and pushes them to the `gpu_display`. */
- void copy_to_gpu_display_naive(GPUDisplay *gpu_display, PassMode pass_mode, int num_samples);
+ /* Naive implementation of the `copy_to_display()` which performs film conversion on the
+ * device, then copies pixels to the host and pushes them to the `display`. */
+ void copy_to_display_naive(PathTraceDisplay *display, PassMode pass_mode, int num_samples);
- /* Implementation of `copy_to_gpu_display()` which uses driver's OpenGL/GPU interoperability
+ /* Implementation of `copy_to_display()` which uses driver's OpenGL/GPU interoperability
* functionality, avoiding copy of pixels to the host. */
- bool copy_to_gpu_display_interop(GPUDisplay *gpu_display, PassMode pass_mode, int num_samples);
+ bool copy_to_display_interop(PathTraceDisplay *display, PassMode pass_mode, int num_samples);
/* Synchronously run film conversion kernel and store display result in the given destination. */
void get_render_tile_film_pixels(const PassAccessor::Destination &destination,
@@ -113,6 +122,13 @@ class PathTraceWorkGPU : public PathTraceWork {
/* Count how many currently scheduled paths can still split. */
int shadow_catcher_count_possible_splits();
+ /* Kernel properties. */
+ bool kernel_uses_sorting(DeviceKernel kernel);
+ bool kernel_creates_shadow_paths(DeviceKernel kernel);
+ bool kernel_creates_ao_paths(DeviceKernel kernel);
+ bool kernel_is_shadow_path(DeviceKernel kernel);
+ int kernel_max_active_main_path_index(DeviceKernel kernel);
+
/* Integrator queue. */
unique_ptr<DeviceQueue> queue_;
@@ -124,13 +140,16 @@ class PathTraceWorkGPU : public PathTraceWork {
/* SoA arrays for integrator state. */
vector<unique_ptr<device_memory>> integrator_state_soa_;
uint integrator_state_soa_kernel_features_;
+ int integrator_state_soa_volume_stack_size_ = 0;
/* Keep track of number of queued kernels. */
device_vector<IntegratorQueueCounter> integrator_queue_counter_;
/* Shader sorting. */
device_vector<int> integrator_shader_sort_counter_;
device_vector<int> integrator_shader_raytrace_sort_counter_;
+ device_vector<int> integrator_shader_sort_prefix_sum_;
/* Path split. */
- device_vector<int> integrator_next_shadow_catcher_path_index_;
+ device_vector<int> integrator_next_main_path_index_;
+ device_vector<int> integrator_next_shadow_path_index_;
/* Temporary buffer to get an array of queued path for a particular kernel. */
device_vector<int> queued_paths_;
@@ -139,9 +158,9 @@ class PathTraceWorkGPU : public PathTraceWork {
/* Temporary buffer for passing work tiles to kernel. */
device_vector<KernelWorkTile> work_tiles_;
- /* Temporary buffer used by the copy_to_gpu_display() whenever graphics interoperability is not
+ /* Temporary buffer used by the copy_to_display() whenever graphics interoperability is not
* available. Is allocated on-demand. */
- device_vector<half4> gpu_display_rgba_half_;
+ device_vector<half4> display_rgba_half_;
unique_ptr<DeviceGraphicsInterop> device_graphics_interop_;
@@ -154,12 +173,12 @@ class PathTraceWorkGPU : public PathTraceWork {
/* Minimum number of paths which keeps the device bust. If the actual number of paths falls below
* this value more work will be scheduled. */
- int min_num_active_paths_;
+ int min_num_active_main_paths_;
/* Maximum path index, effective number of paths used may be smaller than
* the size of the integrator_state_ buffer so can avoid iterating over the
* full buffer. */
- int max_active_path_index_;
+ int max_active_main_path_index_;
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/integrator/render_scheduler.cpp b/intern/cycles/integrator/render_scheduler.cpp
index 322d3d5f94c..f4660448c70 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
@@ -88,6 +88,16 @@ int RenderScheduler::get_num_samples() const
return num_samples_;
}
+void RenderScheduler::set_sample_offset(int sample_offset)
+{
+ sample_offset_ = sample_offset;
+}
+
+int RenderScheduler::get_sample_offset() const
+{
+ return sample_offset_;
+}
+
void RenderScheduler::set_time_limit(double time_limit)
{
time_limit_ = time_limit;
@@ -102,7 +112,7 @@ int RenderScheduler::get_rendered_sample() const
{
DCHECK_GT(get_num_rendered_samples(), 0);
- return start_sample_ + get_num_rendered_samples() - 1;
+ return start_sample_ + get_num_rendered_samples() - 1 - sample_offset_;
}
int RenderScheduler::get_num_rendered_samples() const
@@ -110,13 +120,15 @@ int RenderScheduler::get_num_rendered_samples() const
return state_.num_rendered_samples;
}
-void RenderScheduler::reset(const BufferParams &buffer_params, int num_samples)
+void RenderScheduler::reset(const BufferParams &buffer_params, int num_samples, int sample_offset)
{
buffer_params_ = buffer_params;
update_start_resolution_divider();
set_num_samples(num_samples);
+ set_start_sample(sample_offset);
+ set_sample_offset(sample_offset);
/* In background mode never do lower resolution render preview, as it is not really supported
* by the software. */
@@ -171,7 +183,7 @@ void RenderScheduler::reset(const BufferParams &buffer_params, int num_samples)
void RenderScheduler::reset_for_next_tile()
{
- reset(buffer_params_, num_samples_);
+ reset(buffer_params_, num_samples_, sample_offset_);
}
bool RenderScheduler::render_work_reschedule_on_converge(RenderWork &render_work)
@@ -317,6 +329,7 @@ RenderWork RenderScheduler::get_render_work()
render_work.path_trace.start_sample = get_start_sample_to_path_trace();
render_work.path_trace.num_samples = get_num_samples_to_path_trace();
+ render_work.path_trace.sample_offset = get_sample_offset();
render_work.init_render_buffers = (render_work.path_trace.start_sample == get_start_sample());
@@ -827,6 +840,26 @@ int RenderScheduler::get_num_samples_to_path_trace() const
num_samples_to_occupy = lround(state_.occupancy_num_samples * 0.7f / state_.occupancy);
}
+ /* When time limit is used clamp the calculated number of samples to keep occupancy.
+ * This is because time limit causes the last render iteration to happen with less number of
+ * samples, which conflicts with the occupancy (lower number of samples causes lower
+ * occupancy, also the calculation is based on number of previously rendered samples).
+ *
+ * When time limit is not used the number of samples per render iteration is either increasing
+ * or stays the same, so there is no need to clamp number of samples calculated for occupancy.
+ */
+ if (time_limit_ != 0.0 && state_.start_render_time != 0.0) {
+ const double remaining_render_time = max(
+ 0.0, time_limit_ - (time_dt() - state_.start_render_time));
+ const double time_per_sample_average = path_trace_time_.get_average();
+ const double predicted_render_time = num_samples_to_occupy * time_per_sample_average;
+
+ if (predicted_render_time > remaining_render_time) {
+ num_samples_to_occupy = lround(num_samples_to_occupy *
+ (remaining_render_time / predicted_render_time));
+ }
+ }
+
num_samples_to_render = max(num_samples_to_render,
min(num_samples_to_occupy, max_num_samples_to_render));
}
@@ -841,7 +874,8 @@ int RenderScheduler::get_num_samples_to_path_trace() const
* is to ensure that the final render is pixel-matched regardless of how many samples per second
* compute device can do. */
- return adaptive_sampling_.align_samples(path_trace_start_sample, num_samples_to_render);
+ return adaptive_sampling_.align_samples(path_trace_start_sample - sample_offset_,
+ num_samples_to_render);
}
int RenderScheduler::get_num_samples_during_navigation(int resolution_divider) const
diff --git a/intern/cycles/integrator/render_scheduler.h b/intern/cycles/integrator/render_scheduler.h
index 6ed368a2dc8..d08e077257f 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
@@ -39,6 +39,7 @@ class RenderWork {
struct {
int start_sample = 0;
int num_samples = 0;
+ int sample_offset = 0;
} path_trace;
struct {
@@ -125,6 +126,9 @@ class RenderScheduler {
void set_num_samples(int num_samples);
int get_num_samples() const;
+ void set_sample_offset(int sample_offset);
+ int get_sample_offset() const;
+
/* Time limit for the path tracing tasks, in minutes.
* Zero disables the limit. */
void set_time_limit(double time_limit);
@@ -150,7 +154,7 @@ class RenderScheduler {
/* Reset scheduler, indicating that rendering will happen from scratch.
* Resets current rendered state, as well as scheduling information. */
- void reset(const BufferParams &buffer_params, int num_samples);
+ void reset(const BufferParams &buffer_params, int num_samples, int sample_offset);
/* Reset scheduler upon switching to a next tile.
* Will keep the same number of samples and full-frame render parameters, but will reset progress
@@ -279,7 +283,7 @@ class RenderScheduler {
/* Check whether timing report about the given work need to reset accumulated average time. */
bool work_report_reset_average(const RenderWork &render_work);
- /* CHeck whether render time limit has been reached (or exceeded), and if so store related
+ /* Check whether render time limit has been reached (or exceeded), and if so store related
* information in the state so that rendering is considered finished, and is possible to report
* average render time information. */
void check_time_limit_reached();
@@ -344,7 +348,7 @@ class RenderScheduler {
/* Number of rendered samples on top of the start sample. */
int num_rendered_samples = 0;
- /* Point in time the latest GPUDisplay work has been scheduled. */
+ /* Point in time the latest PathTraceDisplay work has been scheduled. */
double last_display_update_time = 0.0;
/* Value of -1 means display was never updated. */
int last_display_update_sample = -1;
@@ -419,6 +423,8 @@ class RenderScheduler {
int start_sample_ = 0;
int num_samples_ = 0;
+ int sample_offset_ = 0;
+
/* Limit in seconds for how long path tracing is allowed to happen.
* Zero means no limit is applied. */
double time_limit_ = 0.0;
diff --git a/intern/cycles/integrator/shader_eval.cpp b/intern/cycles/integrator/shader_eval.cpp
index a14e41ec5be..95a1adeb016 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
@@ -34,9 +34,10 @@ ShaderEval::ShaderEval(Device *device, Progress &progress) : device_(device), pr
}
bool ShaderEval::eval(const ShaderEvalType type,
- const int max_num_points,
+ const int max_num_inputs,
+ const int num_channels,
const function<int(device_vector<KernelShaderEvalInput> &)> &fill_input,
- const function<void(device_vector<float4> &)> &read_output)
+ const function<void(device_vector<float> &)> &read_output)
{
bool first_device = true;
bool success = true;
@@ -50,26 +51,27 @@ bool ShaderEval::eval(const ShaderEvalType type,
first_device = false;
device_vector<KernelShaderEvalInput> input(device, "ShaderEval input", MEM_READ_ONLY);
- device_vector<float4> output(device, "ShaderEval output", MEM_READ_WRITE);
+ device_vector<float> output(device, "ShaderEval output", MEM_READ_WRITE);
/* Allocate and copy device buffers. */
DCHECK_EQ(input.device, device);
DCHECK_EQ(output.device, device);
DCHECK_LE(output.size(), input.size());
- input.alloc(max_num_points);
+ input.alloc(max_num_inputs);
int num_points = fill_input(input);
if (num_points == 0) {
return;
}
input.copy_to_device();
- output.alloc(num_points);
+ output.alloc(num_points * num_channels);
output.zero_to_device();
/* Evaluate on CPU or GPU. */
- success = (device->info.type == DEVICE_CPU) ? eval_cpu(device, type, input, output) :
- eval_gpu(device, type, input, output);
+ success = (device->info.type == DEVICE_CPU) ?
+ eval_cpu(device, type, input, output, num_points) :
+ eval_gpu(device, type, input, output, num_points);
/* Copy data back from device if not canceled. */
if (success) {
@@ -87,18 +89,18 @@ bool ShaderEval::eval(const ShaderEvalType type,
bool ShaderEval::eval_cpu(Device *device,
const ShaderEvalType type,
device_vector<KernelShaderEvalInput> &input,
- device_vector<float4> &output)
+ device_vector<float> &output,
+ const int64_t work_size)
{
vector<CPUKernelThreadGlobals> kernel_thread_globals;
device->get_cpu_kernel_thread_globals(kernel_thread_globals);
/* Find required kernel function. */
- const CPUKernels &kernels = *(device->get_cpu_kernels());
+ const CPUKernels &kernels = Device::get_cpu_kernels();
/* Simple parallel_for over all work items. */
- const int64_t work_size = output.size();
KernelShaderEvalInput *input_data = input.data();
- float4 *output_data = output.data();
+ float *output_data = output.data();
bool success = true;
tbb::task_arena local_arena(device->info.cpu_threads);
@@ -111,7 +113,7 @@ bool ShaderEval::eval_cpu(Device *device,
}
const int thread_index = tbb::this_task_arena::current_thread_index();
- KernelGlobals *kg = &kernel_thread_globals[thread_index];
+ const KernelGlobalsCPU *kg = &kernel_thread_globals[thread_index];
switch (type) {
case SHADER_EVAL_DISPLACE:
@@ -120,6 +122,9 @@ bool ShaderEval::eval_cpu(Device *device,
case SHADER_EVAL_BACKGROUND:
kernels.shader_eval_background(kg, input_data, output_data, work_index);
break;
+ case SHADER_EVAL_CURVE_SHADOW_TRANSPARENCY:
+ kernels.shader_eval_curve_shadow_transparency(kg, input_data, output_data, work_index);
+ break;
}
});
});
@@ -130,7 +135,8 @@ bool ShaderEval::eval_cpu(Device *device,
bool ShaderEval::eval_gpu(Device *device,
const ShaderEvalType type,
device_vector<KernelShaderEvalInput> &input,
- device_vector<float4> &output)
+ device_vector<float> &output,
+ const int64_t work_size)
{
/* Find required kernel function. */
DeviceKernel kernel;
@@ -141,6 +147,9 @@ bool ShaderEval::eval_gpu(Device *device,
case SHADER_EVAL_BACKGROUND:
kernel = DEVICE_KERNEL_SHADER_EVAL_BACKGROUND;
break;
+ case SHADER_EVAL_CURVE_SHADOW_TRANSPARENCY:
+ kernel = DEVICE_KERNEL_SHADER_EVAL_CURVE_SHADOW_TRANSPARENCY;
+ break;
};
/* Create device queue. */
@@ -149,15 +158,16 @@ bool ShaderEval::eval_gpu(Device *device,
/* Execute work on GPU in chunk, so we can cancel.
* TODO : query appropriate size from device.*/
- const int64_t chunk_size = 65536;
+ const int32_t chunk_size = 65536;
+
+ device_ptr d_input = input.device_pointer;
+ device_ptr d_output = output.device_pointer;
- const int64_t work_size = output.size();
- void *d_input = (void *)input.device_pointer;
- void *d_output = (void *)output.device_pointer;
+ assert(work_size <= 0x7fffffff);
+ for (int32_t d_offset = 0; d_offset < int32_t(work_size); d_offset += chunk_size) {
+ int32_t d_work_size = std::min(chunk_size, int32_t(work_size) - d_offset);
- for (int64_t d_offset = 0; d_offset < work_size; d_offset += chunk_size) {
- int64_t d_work_size = std::min(chunk_size, work_size - d_offset);
- void *args[] = {&d_input, &d_output, &d_offset, &d_work_size};
+ DeviceKernelArguments args(&d_input, &d_output, &d_offset, &d_work_size);
queue->enqueue(kernel, d_work_size, args);
queue->synchronize();
diff --git a/intern/cycles/integrator/shader_eval.h b/intern/cycles/integrator/shader_eval.h
index 7dbf334b8d7..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
@@ -30,6 +30,7 @@ class Progress;
enum ShaderEvalType {
SHADER_EVAL_DISPLACE,
SHADER_EVAL_BACKGROUND,
+ SHADER_EVAL_CURVE_SHADOW_TRANSPARENCY,
};
/* ShaderEval class performs shader evaluation for background light and displacement. */
@@ -40,19 +41,22 @@ class ShaderEval {
/* Evaluate shader at points specified by KernelShaderEvalInput and write out
* RGBA colors to output. */
bool eval(const ShaderEvalType type,
- const int max_num_points,
+ const int max_num_inputs,
+ const int num_channels,
const function<int(device_vector<KernelShaderEvalInput> &)> &fill_input,
- const function<void(device_vector<float4> &)> &read_output);
+ const function<void(device_vector<float> &)> &read_output);
protected:
bool eval_cpu(Device *device,
const ShaderEvalType type,
device_vector<KernelShaderEvalInput> &input,
- device_vector<float4> &output);
+ device_vector<float> &output,
+ const int64_t work_size);
bool eval_gpu(Device *device,
const ShaderEvalType type,
device_vector<KernelShaderEvalInput> &input,
- device_vector<float4> &output);
+ device_vector<float> &output,
+ const int64_t work_size);
Device *device_;
Progress &progress_;
diff --git a/intern/cycles/integrator/tile.cpp b/intern/cycles/integrator/tile.cpp
index 3387b7bedf1..e9a3cbd38aa 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
@@ -46,9 +46,11 @@ ccl_device_inline uint round_up_to_power_of_two(uint x)
return next_power_of_two(x);
}
-TileSize tile_calculate_best_size(const int2 &image_size,
+TileSize tile_calculate_best_size(const bool accel_rt,
+ 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 +73,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 && accel_rt) {
+ /* 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 +102,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..05b1e0af6b1 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
@@ -49,8 +49,10 @@ std::ostream &operator<<(std::ostream &os, const TileSize &tile_size);
* of active path states.
* Will attempt to provide best guess to keep path tracing threads of a device as localized as
* possible, and have as many threads active for every tile as possible. */
-TileSize tile_calculate_best_size(const int2 &image_size,
+TileSize tile_calculate_best_size(const bool accel_rt,
+ 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 e6ada2f46ee..353c357475d 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
@@ -28,18 +28,28 @@ WorkTileScheduler::WorkTileScheduler()
{
}
+void WorkTileScheduler::set_accelerated_rt(bool accelerated_rt)
+{
+ accelerated_rt_ = accelerated_rt;
+}
+
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,
+ int sample_offset,
+ 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;
@@ -47,6 +57,7 @@ void WorkTileScheduler::reset(const BufferParams &buffer_params, int sample_star
/* Samples parameters. */
sample_start_ = sample_start;
samples_num_ = samples_num;
+ sample_offset_ = sample_offset;
/* Initialize new scheduling. */
reset_scheduler_state();
@@ -54,7 +65,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(
+ accelerated_rt_, image_size_px_, samples_num_, max_num_path_states_, scrambling_distance_);
VLOG(3) << "Will schedule tiles of size " << tile_size_;
@@ -88,7 +100,7 @@ bool WorkTileScheduler::get_work(KernelWorkTile *work_tile_, const int max_work_
DCHECK_NE(max_num_path_states_, 0);
- const int work_index = atomic_fetch_and_add_int32(&next_work_index_, 1);
+ const int work_index = next_work_index_++;
if (work_index >= total_work_size_) {
return false;
}
@@ -106,6 +118,7 @@ bool WorkTileScheduler::get_work(KernelWorkTile *work_tile_, const int max_work_
work_tile.h = tile_size_.height;
work_tile.start_sample = sample_start_ + start_sample;
work_tile.num_samples = min(tile_size_.num_samples, samples_num_ - start_sample);
+ work_tile.sample_offset = sample_offset_;
work_tile.offset = offset_;
work_tile.stride = stride_;
@@ -121,12 +134,8 @@ bool WorkTileScheduler::get_work(KernelWorkTile *work_tile_, const int max_work_
if (max_work_size && tile_work_size > max_work_size) {
/* The work did not fit into the requested limit of the work size. Unschedule the tile,
- * allowing others (or ourselves later one) to pick it up.
- *
- * TODO: Such temporary decrement is not ideal, since it might lead to situation when another
- * device sees there is nothing to be done, finishing its work and leaving all work to be
- * done by us. */
- atomic_fetch_and_add_int32(&next_work_index_, -1);
+ * so it can be picked up again later. */
+ next_work_index_--;
return false;
}
diff --git a/intern/cycles/integrator/work_tile_scheduler.h b/intern/cycles/integrator/work_tile_scheduler.h
index 85f11b601c7..b9cef7be7c4 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
@@ -31,6 +31,9 @@ class WorkTileScheduler {
public:
WorkTileScheduler();
+ /* To indicate if there is accelerated RT support. */
+ void set_accelerated_rt(bool state);
+
/* MAximum path states which are allowed to be used by a single scheduled work tile.
*
* Affects the scheduled work size: the work size will be as big as possible, but will not exceed
@@ -38,7 +41,11 @@ 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,
+ int sample_offset,
+ 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
@@ -51,6 +58,9 @@ class WorkTileScheduler {
protected:
void reset_scheduler_state();
+ /* Used to indicate if there is accelerated ray tracing. */
+ bool accelerated_rt_ = false;
+
/* Maximum allowed path states to be used.
*
* TODO(sergey): Naming can be improved. The fact that this is a limiting factor based on the
@@ -68,11 +78,15 @@ 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). */
int sample_start_ = 0;
int samples_num_ = 0;
+ int sample_offset_ = 0;
/* Tile size which be scheduled for rendering. */
TileSize tile_size_;
diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt
index 7b56216e887..51158b86c5a 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,24 @@ 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
- 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_KERNEL_DEVICE_METAL
+ device/metal/kernel.metal
)
-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_KERNEL_DEVICE_OPTIX
+ device/optix/kernel.cu
+ device/optix/kernel_shader_raytrace.cu
)
-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 +56,41 @@ 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_DEVICE_METAL_HEADERS
+ device/metal/compat.h
+ device/metal/context_begin.h
+ device/metal/context_end.h
+ device/metal/globals.h
+)
+
+set(SRC_KERNEL_CLOSURE_HEADERS
closure/alloc.h
closure/bsdf.h
closure/bsdf_ashikhmin_velvet.h
@@ -147,154 +116,238 @@ 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_point.h
+ geom/motion_triangle.h
+ geom/motion_triangle_intersect.h
+ geom/motion_triangle_shader.h
+ geom/object.h
+ geom/patch.h
+ geom/point.h
+ geom/point_intersect.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
+ bvh/metal.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_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_state.h
- integrator/integrator_state_flow.h
- integrator/integrator_state_template.h
- integrator/integrator_state_util.h
- integrator/integrator_subsurface.h
- integrator/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
+ tables.h
+ textures.h
+ types.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
@@ -328,14 +381,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)
@@ -367,12 +415,8 @@ if(WITH_CYCLES_CUDA_BINARIES)
-I ${CMAKE_CURRENT_SOURCE_DIR}/..
-I ${CMAKE_CURRENT_SOURCE_DIR}/device/cuda
--use_fast_math
- -o ${CMAKE_CURRENT_BINARY_DIR}/${cuda_file})
-
- if(${experimental})
- set(cuda_flags ${cuda_flags} -D __KERNEL_EXPERIMENTAL__)
- set(name ${name}_experimental)
- endif()
+ -o ${CMAKE_CURRENT_BINARY_DIR}/${cuda_file}
+ -Wno-deprecated-gpu-targets)
if(WITH_NANOVDB)
set(cuda_flags ${cuda_flags}
@@ -380,6 +424,10 @@ if(WITH_CYCLES_CUDA_BINARIES)
-I "${NANOVDB_INCLUDE_DIR}")
endif()
+ if(WITH_CYCLES_DEBUG)
+ set(cuda_flags ${cuda_flags} -D WITH_CYCLES_DEBUG)
+ endif()
+
if(WITH_CYCLES_CUBIN_COMPILER)
string(SUBSTRING ${arch} 3 -1 CUDA_ARCH)
@@ -404,16 +452,27 @@ if(WITH_CYCLES_CUDA_BINARIES)
-cuda-toolkit-dir "${cuda_toolkit_root_dir}"
DEPENDS ${kernel_sources} cycles_cubin_cc)
else()
- add_custom_command(
- OUTPUT ${cuda_file}
- COMMAND ${cuda_nvcc_executable}
+ set(_cuda_nvcc_args
-arch=${arch}
${CUDA_NVCC_FLAGS}
--${format}
${CMAKE_CURRENT_SOURCE_DIR}${cuda_kernel_src}
--ptxas-options="-v"
- ${cuda_flags}
- DEPENDS ${kernel_sources})
+ ${cuda_flags})
+
+ if(WITH_COMPILER_CCACHE AND CCACHE_PROGRAM)
+ add_custom_command(
+ OUTPUT ${cuda_file}
+ COMMAND ${CCACHE_PROGRAM} ${cuda_nvcc_executable} ${_cuda_nvcc_args}
+ DEPENDS ${kernel_sources})
+ else()
+ add_custom_command(
+ OUTPUT ${cuda_file}
+ COMMAND ${cuda_nvcc_executable} ${_cuda_nvcc_args}
+ DEPENDS ${kernel_sources})
+ endif()
+
+ unset(_cuda_nvcc_args)
endif()
delayed_install("${CMAKE_CURRENT_BINARY_DIR}" "${cuda_file}" ${CYCLES_INSTALL_PATH}/lib)
list(APPEND cuda_cubins ${cuda_file})
@@ -472,93 +531,72 @@ endif()
# HIP module
-if(WITH_CYCLES_HIP_BINARIES)
- # 64 bit only
- set(HIP_BITS 64)
-
- # HIP version
- execute_process(COMMAND ${HIP_HIPCC_EXECUTABLE} "--version" OUTPUT_VARIABLE HIPCC_OUT)
- string(REGEX REPLACE ".*release ([0-9]+)\\.([0-9]+).*" "\\1" HIP_VERSION_MAJOR "${HIPCC_OUT}")
- string(REGEX REPLACE ".*release ([0-9]+)\\.([0-9]+).*" "\\2" HIP_VERSION_MINOR "${HIPCC_OUT}")
- set(HIP_VERSION "${HIP_VERSION_MAJOR}${HIP_VERSION_MINOR}")
-
-
- message(WARNING
- "HIP version ${HIP_VERSION_MAJOR}.${HIP_VERSION_MINOR} detected")
-
+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)
- macro(CYCLES_HIP_KERNEL_ADD arch prev_arch name flags sources experimental)
- if(${arch} MATCHES "compute_.*")
- set(format "ptx")
- else()
- set(format "fatbin")
- endif()
+ macro(CYCLES_HIP_KERNEL_ADD arch name flags sources experimental)
+ set(format "fatbin")
set(hip_file ${name}_${arch}.${format})
-
set(kernel_sources ${sources})
- if(NOT ${prev_arch} STREQUAL "none")
- if(${prev_arch} MATCHES "compute_.*")
- set(kernel_sources ${kernel_sources} ${name}_${prev_arch}.ptx)
- else()
- set(kernel_sources ${kernel_sources} ${name}_${prev_arch}.fatbin)
- endif()
- endif()
set(hip_kernel_src "/device/hip/${name}.cpp")
- set(hip_flags ${flags}
+ if(WIN32)
+ set(hip_command ${CMAKE_COMMAND})
+ set(hip_flags
+ -E env "HIP_PATH=${HIP_ROOT_DIR}" "PATH=${HIP_PERL_DIR}"
+ ${HIP_HIPCC_EXECUTABLE}.bat)
+ else()
+ set(hip_command ${HIP_HIPCC_EXECUTABLE})
+ set(hip_flags)
+ endif()
+
+ set(hip_flags
+ ${hip_flags}
+ --amdgpu-target=${arch}
+ ${HIP_HIPCC_FLAGS}
+ --genco
+ ${CMAKE_CURRENT_SOURCE_DIR}${hip_kernel_src}
+ ${flags}
-D CCL_NAMESPACE_BEGIN=
-D CCL_NAMESPACE_END=
-D HIPCC
- -m ${HIP_BITS}
-I ${CMAKE_CURRENT_SOURCE_DIR}/..
-I ${CMAKE_CURRENT_SOURCE_DIR}/device/hip
- --use_fast_math
+ -Wno-parentheses-equality
+ -Wno-unused-value
+ --hipcc-func-supp
+ -ffast-math
-o ${CMAKE_CURRENT_BINARY_DIR}/${hip_file})
- if(${experimental})
- set(hip_flags ${hip_flags} -D __KERNEL_EXPERIMENTAL__)
- set(name ${name}_experimental)
- endif()
-
- if(WITH_CYCLES_DEBUG)
- set(hip_flags ${hip_flags} -D __KERNEL_DEBUG__)
- endif()
-
if(WITH_NANOVDB)
set(hip_flags ${hip_flags}
-D WITH_NANOVDB
-I "${NANOVDB_INCLUDE_DIR}")
endif()
- endmacro()
- set(prev_arch "none")
- foreach(arch ${CYCLES_HIP_BINARIES_ARCH})
- set(hip_hipcc_executable ${HIP_HIPCC_EXECUTABLE})
- set(hip_toolkit_root_dir ${HIP_TOOLKIT_ROOT_DIR})
- if(DEFINED hip_hipcc_executable AND DEFINED hip_toolkit_root_dir)
- # Compile regular kernel
- CYCLES_HIP_KERNEL_ADD(${arch} ${prev_arch} kernel "" "${hip_sources}" FALSE)
+ if(WITH_CYCLES_DEBUG)
+ set(hip_flags ${hip_flags} -D WITH_CYCLES_DEBUG)
+ endif()
- if(WITH_CYCLES_HIP_BUILD_SERIAL)
- set(prev_arch ${arch})
- endif()
+ add_custom_command(
+ OUTPUT ${hip_file}
+ COMMAND ${hip_command} ${hip_flags}
+ DEPENDS ${kernel_sources})
+ delayed_install("${CMAKE_CURRENT_BINARY_DIR}" "${hip_file}" ${CYCLES_INSTALL_PATH}/lib)
+ list(APPEND hip_fatbins ${hip_file})
+ endmacro()
- unset(hip_hipcc_executable)
- unset(hip_toolkit_root_dir)
- endif()
+ foreach(arch ${CYCLES_HIP_BINARIES_ARCH})
+ # Compile regular kernel
+ CYCLES_HIP_KERNEL_ADD(${arch} kernel "" "${hip_sources}" FALSE)
endforeach()
add_custom_target(cycles_kernel_hip ALL DEPENDS ${hip_fatbins})
@@ -586,6 +624,10 @@ if(WITH_CYCLES_DEVICE_OPTIX AND WITH_CYCLES_CUDA_BINARIES)
-I "${NANOVDB_INCLUDE_DIR}")
endif()
+ if(WITH_CYCLES_DEBUG)
+ set(cuda_flags ${cuda_flags} -D WITH_CYCLES_DEBUG)
+ endif()
+
if(WITH_CYCLES_CUBIN_COMPILER)
# Needed to find libnvrtc-builtins.so. Can't do it from inside
# cycles_cubin_cc since the env variable is read before main()
@@ -601,15 +643,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>"
@@ -626,15 +663,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}
@@ -670,7 +702,7 @@ if(WITH_CYCLES_OSL)
cycles_kernel_osl
)
add_subdirectory(osl)
- add_subdirectory(shaders)
+ add_subdirectory(osl/shaders)
endif()
# CPU module
@@ -684,7 +716,7 @@ if(WITH_COMPILER_ASAN)
string(APPEND CMAKE_CXX_FLAGS_RELWITHDEBINFO " -fno-sanitize=all")
string(APPEND CMAKE_CXX_FLAGS_DEBUG " -fno-sanitize=vptr")
elseif(CMAKE_C_COMPILER_ID MATCHES "Clang")
- # With OSL, Cycles disables rtti in some modules, wich then breaks at linking
+ # With OSL, Cycles disables rtti in some modules, which then breaks at linking
# when trying to use vptr sanitizer (included into 'undefined' general option).
string(APPEND CMAKE_CXX_FLAGS_RELWITHDEBINFO " -fno-sanitize=vptr")
string(APPEND CMAKE_CXX_FLAGS_DEBUG " -fno-sanitize=vptr")
@@ -708,34 +740,38 @@ 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_DEVICE_METAL}
+ ${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}
+ ${SRC_KERNEL_DEVICE_METAL_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("device\\metal" FILES ${SRC_KERNEL_DEVICE_METAL} ${SRC_KERNEL_DEVICE_METAL_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)
@@ -749,19 +785,27 @@ 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_DEVICE_METAL}" ${CYCLES_INSTALL_PATH}/source/kernel/device/metal)
+delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNEL_DEVICE_METAL_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/device/metal)
+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 0b44cc5db34..1797bf60720 100644
--- a/intern/cycles/kernel/bvh/bvh.h
+++ b/intern/cycles/kernel/bvh/bvh.h
@@ -28,40 +28,46 @@
#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"
+#ifdef __METALRT__
+# include "kernel/bvh/metal.h"
+#endif
+
+#include "kernel/bvh/types.h"
+#include "kernel/bvh/util.h"
+
+#include "kernel/integrator/state_util.h"
CCL_NAMESPACE_BEGIN
-#ifndef __KERNEL_OPTIX__
+#if !defined(__KERNEL_GPU_RAYTRACING__)
/* 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"
+# define BVH_FUNCTION_FEATURES BVH_POINTCLOUD
+# 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"
+# define BVH_FUNCTION_FEATURES BVH_HAIR | BVH_POINTCLOUD
+# 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"
+# define BVH_FUNCTION_FEATURES BVH_MOTION | BVH_POINTCLOUD
+# 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"
+# define BVH_FUNCTION_FEATURES BVH_HAIR | BVH_MOTION | BVH_POINTCLOUD
+# include "kernel/bvh/traversal.h"
# endif
/* Subsurface scattering BVH traversal */
@@ -69,12 +75,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__ */
@@ -83,12 +89,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__ */
@@ -96,26 +102,27 @@ 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"
+# define BVH_FUNCTION_FEATURES BVH_POINTCLOUD
+# 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"
+# define BVH_FUNCTION_FEATURES BVH_HAIR | BVH_POINTCLOUD
+# 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"
+# define BVH_FUNCTION_FEATURES BVH_MOTION | BVH_POINTCLOUD
+# 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"
+# define BVH_FUNCTION_FEATURES BVH_HAIR | BVH_MOTION | BVH_POINTCLOUD
+# include "kernel/bvh/shadow_all.h"
# endif
+
# endif /* __SHADOW_RECORD_ALL__ */
/* Record all intersections - Volume BVH traversal. */
@@ -123,12 +130,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__ */
@@ -137,9 +144,9 @@ CCL_NAMESPACE_BEGIN
# undef BVH_NAME_EVAL
# undef BVH_FUNCTION_FULL_NAME
-#endif /* __KERNEL_OPTIX__ */
+#endif /* !defined(__KERNEL_GPU_RAYTRACING__) */
-ccl_device_inline bool scene_intersect_valid(const Ray *ray)
+ccl_device_inline bool scene_intersect_valid(ccl_private const Ray *ray)
{
/* NOTE: Due to some vectorization code non-finite origin point might
* cause lots of false-positive intersections which will overflow traversal
@@ -154,10 +161,10 @@ ccl_device_inline bool scene_intersect_valid(const Ray *ray)
return isfinite_safe(ray->P.x) && isfinite_safe(ray->D.x) && len_squared(ray->D) != 0.0f;
}
-ccl_device_intersect bool scene_intersect(const KernelGlobals *kg,
- const Ray *ray,
+ccl_device_intersect bool scene_intersect(KernelGlobals kg,
+ ccl_private const Ray *ray,
const uint visibility,
- Intersection *isect)
+ ccl_private Intersection *isect)
{
#ifdef __KERNEL_OPTIX__
uint p0 = 0;
@@ -166,15 +173,16 @@ ccl_device_intersect bool scene_intersect(const KernelGlobals *kg,
uint p3 = 0;
uint p4 = visibility;
uint p5 = PRIMITIVE_NONE;
+ uint p6 = ((uint64_t)ray) & 0xFFFFFFFF;
+ uint p7 = (((uint64_t)ray) >> 32) & 0xFFFFFFFF;
uint ray_mask = visibility & 0xFF;
- uint ray_flags = OPTIX_RAY_FLAG_NONE;
+ uint ray_flags = OPTIX_RAY_FLAG_ENFORCE_ANYHIT;
if (0 == ray_mask && (visibility & ~0xFF) != 0) {
ray_mask = 0xFF;
- ray_flags = OPTIX_RAY_FLAG_ENFORCE_ANYHIT;
}
else if (visibility & PATH_RAY_SHADOW_OPAQUE) {
- ray_flags = OPTIX_RAY_FLAG_TERMINATE_ON_FIRST_HIT;
+ ray_flags |= OPTIX_RAY_FLAG_TERMINATE_ON_FIRST_HIT;
}
optixTrace(scene_intersect_valid(ray) ? kernel_data.bvh.scene : 0,
@@ -193,7 +201,9 @@ ccl_device_intersect bool scene_intersect(const KernelGlobals *kg,
p2,
p3,
p4,
- p5);
+ p5,
+ p6,
+ p7);
isect->t = __uint_as_float(p0);
isect->u = __uint_as_float(p1);
@@ -203,7 +213,96 @@ ccl_device_intersect bool scene_intersect(const KernelGlobals *kg,
isect->type = p5;
return p5 != PRIMITIVE_NONE;
-#else /* __KERNEL_OPTIX__ */
+#elif defined(__METALRT__)
+
+ if (!scene_intersect_valid(ray)) {
+ isect->t = ray->t;
+ isect->type = PRIMITIVE_NONE;
+ return false;
+ }
+
+# if defined(__KERNEL_DEBUG__)
+ if (is_null_instance_acceleration_structure(metal_ancillaries->accel_struct)) {
+ isect->t = ray->t;
+ isect->type = PRIMITIVE_NONE;
+ kernel_assert(!"Invalid metal_ancillaries->accel_struct pointer");
+ return false;
+ }
+
+ if (is_null_intersection_function_table(metal_ancillaries->ift_default)) {
+ isect->t = ray->t;
+ isect->type = PRIMITIVE_NONE;
+ kernel_assert(!"Invalid ift_default");
+ return false;
+ }
+# endif
+
+ metal::raytracing::ray r(ray->P, ray->D, 0.0f, ray->t);
+ metalrt_intersector_type metalrt_intersect;
+
+ if (!kernel_data.bvh.have_curves) {
+ metalrt_intersect.assume_geometry_type(metal::raytracing::geometry_type::triangle);
+ }
+
+ MetalRTIntersectionPayload payload;
+ payload.self = ray->self;
+ payload.u = 0.0f;
+ payload.v = 0.0f;
+ payload.visibility = visibility;
+
+ typename metalrt_intersector_type::result_type intersection;
+
+ uint ray_mask = visibility & 0xFF;
+ if (0 == ray_mask && (visibility & ~0xFF) != 0) {
+ ray_mask = 0xFF;
+ /* No further intersector setup required: Default MetalRT behavior is any-hit. */
+ }
+ else if (visibility & PATH_RAY_SHADOW_OPAQUE) {
+ /* No further intersector setup required: Shadow ray early termination is controlled by the
+ * intersection handler */
+ }
+
+# if defined(__METALRT_MOTION__)
+ payload.time = ray->time;
+ intersection = metalrt_intersect.intersect(r,
+ metal_ancillaries->accel_struct,
+ ray_mask,
+ ray->time,
+ metal_ancillaries->ift_default,
+ payload);
+# else
+ intersection = metalrt_intersect.intersect(
+ r, metal_ancillaries->accel_struct, ray_mask, metal_ancillaries->ift_default, payload);
+# endif
+
+ if (intersection.type == intersection_type::none) {
+ isect->t = ray->t;
+ isect->type = PRIMITIVE_NONE;
+
+ return false;
+ }
+
+ isect->t = intersection.distance;
+
+ isect->prim = payload.prim;
+ isect->type = payload.type;
+ isect->object = intersection.user_instance_id;
+
+ isect->t = intersection.distance;
+ if (intersection.type == intersection_type::triangle) {
+ isect->u = 1.0f - intersection.triangle_barycentric_coord.y -
+ intersection.triangle_barycentric_coord.x;
+ isect->v = intersection.triangle_barycentric_coord.x;
+ }
+ else {
+ isect->u = payload.u;
+ isect->v = payload.v;
+ }
+
+ return isect->type != PRIMITIVE_NONE;
+
+#else
+
if (!scene_intersect_valid(ray)) {
return false;
}
@@ -214,6 +313,7 @@ ccl_device_intersect bool scene_intersect(const KernelGlobals *kg,
CCLIntersectContext ctx(kg, CCLIntersectContext::RAY_REGULAR);
IntersectContext rtc_ctx(&ctx);
RTCRayHit ray_hit;
+ ctx.ray = ray;
kernel_embree_setup_rayhit(*ray, ray_hit, visibility);
rtcIntersect1(kernel_data.bvh.scene, &rtc_ctx.context, &ray_hit);
if (ray_hit.hit.geomID != RTC_INVALID_GEOMETRY_ID &&
@@ -248,19 +348,22 @@ ccl_device_intersect bool scene_intersect(const KernelGlobals *kg,
}
#ifdef __BVH_LOCAL__
-ccl_device_intersect bool scene_intersect_local(const KernelGlobals *kg,
- const Ray *ray,
- LocalIntersection *local_isect,
+ccl_device_intersect bool scene_intersect_local(KernelGlobals kg,
+ ccl_private const Ray *ray,
+ ccl_private LocalIntersection *local_isect,
int local_object,
- uint *lcg_state,
+ ccl_private uint *lcg_state,
int max_hits)
{
# ifdef __KERNEL_OPTIX__
- uint p0 = ((uint64_t)lcg_state) & 0xFFFFFFFF;
- uint p1 = (((uint64_t)lcg_state) >> 32) & 0xFFFFFFFF;
- uint p2 = ((uint64_t)local_isect) & 0xFFFFFFFF;
- uint p3 = (((uint64_t)local_isect) >> 32) & 0xFFFFFFFF;
+ uint p0 = pointer_pack_to_uint_0(lcg_state);
+ uint p1 = pointer_pack_to_uint_1(lcg_state);
+ uint p2 = pointer_pack_to_uint_0(local_isect);
+ uint p3 = pointer_pack_to_uint_1(local_isect);
uint p4 = local_object;
+ uint p6 = ((uint64_t)ray) & 0xFFFFFFFF;
+ uint p7 = (((uint64_t)ray) >> 32) & 0xFFFFFFFF;
+
/* Is set to zero on miss or if ray is aborted, so can be used as return value. */
uint p5 = max_hits;
@@ -284,10 +387,75 @@ ccl_device_intersect bool scene_intersect_local(const KernelGlobals *kg,
p2,
p3,
p4,
- p5);
+ p5,
+ p6,
+ p7);
return p5;
-# else /* __KERNEL_OPTIX__ */
+# elif defined(__METALRT__)
+ if (!scene_intersect_valid(ray)) {
+ if (local_isect) {
+ local_isect->num_hits = 0;
+ }
+ return false;
+ }
+
+# if defined(__KERNEL_DEBUG__)
+ if (is_null_instance_acceleration_structure(metal_ancillaries->accel_struct)) {
+ if (local_isect) {
+ local_isect->num_hits = 0;
+ }
+ kernel_assert(!"Invalid metal_ancillaries->accel_struct pointer");
+ return false;
+ }
+
+ if (is_null_intersection_function_table(metal_ancillaries->ift_local)) {
+ if (local_isect) {
+ local_isect->num_hits = 0;
+ }
+ kernel_assert(!"Invalid ift_local");
+ return false;
+ }
+# endif
+
+ metal::raytracing::ray r(ray->P, ray->D, 0.0f, ray->t);
+ metalrt_intersector_type metalrt_intersect;
+
+ metalrt_intersect.force_opacity(metal::raytracing::forced_opacity::non_opaque);
+ if (!kernel_data.bvh.have_curves) {
+ metalrt_intersect.assume_geometry_type(metal::raytracing::geometry_type::triangle);
+ }
+
+ MetalRTIntersectionLocalPayload payload;
+ payload.self = ray->self;
+ payload.local_object = local_object;
+ payload.max_hits = max_hits;
+ payload.local_isect.num_hits = 0;
+ if (lcg_state) {
+ payload.has_lcg_state = true;
+ payload.lcg_state = *lcg_state;
+ }
+ payload.result = false;
+
+ typename metalrt_intersector_type::result_type intersection;
+
+# if defined(__METALRT_MOTION__)
+ intersection = metalrt_intersect.intersect(
+ r, metal_ancillaries->accel_struct, 0xFF, ray->time, metal_ancillaries->ift_local, payload);
+# else
+ intersection = metalrt_intersect.intersect(
+ r, metal_ancillaries->accel_struct, 0xFF, metal_ancillaries->ift_local, payload);
+# endif
+
+ if (lcg_state) {
+ *lcg_state = payload.lcg_state;
+ }
+ *local_isect = payload.local_isect;
+
+ return payload.result;
+
+# else
+
if (!scene_intersect_valid(ray)) {
if (local_isect) {
local_isect->num_hits = 0;
@@ -303,6 +471,7 @@ ccl_device_intersect bool scene_intersect_local(const KernelGlobals *kg,
kg, has_bvh ? CCLIntersectContext::RAY_SSS : CCLIntersectContext::RAY_LOCAL);
ctx.lcg_state = lcg_state;
ctx.max_hits = max_hits;
+ ctx.ray = ray;
ctx.local_isect = local_isect;
if (local_isect) {
local_isect->num_hits = 0;
@@ -360,26 +529,29 @@ ccl_device_intersect bool scene_intersect_local(const KernelGlobals *kg,
#endif
#ifdef __SHADOW_RECORD_ALL__
-ccl_device_intersect bool scene_intersect_shadow_all(const KernelGlobals *kg,
- const Ray *ray,
- Intersection *isect,
+ccl_device_intersect bool scene_intersect_shadow_all(KernelGlobals kg,
+ IntegratorShadowState state,
+ ccl_private const Ray *ray,
uint visibility,
uint max_hits,
- uint *num_hits)
+ ccl_private uint *num_recorded_hits,
+ ccl_private float *throughput)
{
# ifdef __KERNEL_OPTIX__
- uint p0 = ((uint64_t)isect) & 0xFFFFFFFF;
- uint p1 = (((uint64_t)isect) >> 32) & 0xFFFFFFFF;
+ uint p0 = state;
+ uint p1 = __float_as_uint(1.0f); /* Throughput. */
+ uint p2 = 0; /* Number of hits. */
uint p3 = max_hits;
uint p4 = visibility;
uint p5 = false;
+ uint p6 = ((uint64_t)ray) & 0xFFFFFFFF;
+ uint p7 = (((uint64_t)ray) >> 32) & 0xFFFFFFFF;
uint ray_mask = visibility & 0xFF;
if (0 == ray_mask && (visibility & ~0xFF) != 0) {
ray_mask = 0xFF;
}
- *num_hits = 0; /* Initialize hit count to zero. */
optixTrace(scene_intersect_valid(ray) ? kernel_data.bvh.scene : 0,
ray->P,
ray->D,
@@ -394,29 +566,99 @@ ccl_device_intersect bool scene_intersect_shadow_all(const KernelGlobals *kg,
0,
p0,
p1,
- *num_hits,
+ p2,
p3,
p4,
- p5);
+ p5,
+ p6,
+ p7);
+
+ *num_recorded_hits = uint16_unpack_from_uint_0(p2);
+ *throughput = __uint_as_float(p1);
return p5;
-# else /* __KERNEL_OPTIX__ */
+# elif defined(__METALRT__)
+
if (!scene_intersect_valid(ray)) {
- *num_hits = 0;
+ return false;
+ }
+
+# if defined(__KERNEL_DEBUG__)
+ if (is_null_instance_acceleration_structure(metal_ancillaries->accel_struct)) {
+ kernel_assert(!"Invalid metal_ancillaries->accel_struct pointer");
+ return false;
+ }
+
+ if (is_null_intersection_function_table(metal_ancillaries->ift_shadow)) {
+ kernel_assert(!"Invalid ift_shadow");
+ return false;
+ }
+# endif
+
+ metal::raytracing::ray r(ray->P, ray->D, 0.0f, ray->t);
+ metalrt_intersector_type metalrt_intersect;
+
+ metalrt_intersect.force_opacity(metal::raytracing::forced_opacity::non_opaque);
+ if (!kernel_data.bvh.have_curves) {
+ metalrt_intersect.assume_geometry_type(metal::raytracing::geometry_type::triangle);
+ }
+
+ MetalRTIntersectionShadowPayload payload;
+ payload.self = ray->self;
+ payload.visibility = visibility;
+ payload.max_hits = max_hits;
+ payload.num_hits = 0;
+ payload.num_recorded_hits = 0;
+ payload.throughput = 1.0f;
+ payload.result = false;
+ payload.state = state;
+
+ uint ray_mask = visibility & 0xFF;
+ if (0 == ray_mask && (visibility & ~0xFF) != 0) {
+ ray_mask = 0xFF;
+ }
+
+ typename metalrt_intersector_type::result_type intersection;
+
+# if defined(__METALRT_MOTION__)
+ payload.time = ray->time;
+ intersection = metalrt_intersect.intersect(r,
+ metal_ancillaries->accel_struct,
+ ray_mask,
+ ray->time,
+ metal_ancillaries->ift_shadow,
+ payload);
+# else
+ intersection = metalrt_intersect.intersect(
+ r, metal_ancillaries->accel_struct, ray_mask, metal_ancillaries->ift_shadow, payload);
+# endif
+
+ *num_recorded_hits = payload.num_recorded_hits;
+ *throughput = payload.throughput;
+
+ return payload.result;
+
+# else
+ if (!scene_intersect_valid(ray)) {
+ *num_recorded_hits = 0;
+ *throughput = 1.0f;
return false;
}
# ifdef __EMBREE__
if (kernel_data.bvh.scene) {
CCLIntersectContext ctx(kg, CCLIntersectContext::RAY_SHADOW_ALL);
- ctx.isect_s = isect;
+ Intersection *isect_array = (Intersection *)state->shadow_isect;
+ ctx.isect_s = isect_array;
ctx.max_hits = max_hits;
+ ctx.ray = ray;
IntersectContext rtc_ctx(&ctx);
RTCRay rtc_ray;
kernel_embree_setup_ray(*ray, rtc_ray, visibility);
rtcOccluded1(kernel_data.bvh.scene, &rtc_ctx.context, &rtc_ray);
- *num_hits = ctx.num_hits;
+ *num_recorded_hits = ctx.num_recorded_hits;
+ *throughput = ctx.throughput;
return ctx.opaque_hit;
}
# endif /* __EMBREE__ */
@@ -425,29 +667,33 @@ ccl_device_intersect bool scene_intersect_shadow_all(const KernelGlobals *kg,
if (kernel_data.bvh.have_motion) {
# ifdef __HAIR__
if (kernel_data.bvh.have_curves) {
- return bvh_intersect_shadow_all_hair_motion(kg, ray, isect, visibility, max_hits, num_hits);
+ return bvh_intersect_shadow_all_hair_motion(
+ kg, ray, state, visibility, max_hits, num_recorded_hits, throughput);
}
# endif /* __HAIR__ */
- return bvh_intersect_shadow_all_motion(kg, ray, isect, visibility, max_hits, num_hits);
+ return bvh_intersect_shadow_all_motion(
+ kg, ray, state, visibility, max_hits, num_recorded_hits, throughput);
}
# endif /* __OBJECT_MOTION__ */
# ifdef __HAIR__
if (kernel_data.bvh.have_curves) {
- return bvh_intersect_shadow_all_hair(kg, ray, isect, visibility, max_hits, num_hits);
+ return bvh_intersect_shadow_all_hair(
+ kg, ray, state, visibility, max_hits, num_recorded_hits, throughput);
}
# endif /* __HAIR__ */
- return bvh_intersect_shadow_all(kg, ray, isect, visibility, max_hits, num_hits);
+ return bvh_intersect_shadow_all(
+ kg, ray, state, visibility, max_hits, num_recorded_hits, throughput);
# endif /* __KERNEL_OPTIX__ */
}
#endif /* __SHADOW_RECORD_ALL__ */
#ifdef __VOLUME__
-ccl_device_intersect bool scene_intersect_volume(const KernelGlobals *kg,
- const Ray *ray,
- Intersection *isect,
+ccl_device_intersect bool scene_intersect_volume(KernelGlobals kg,
+ ccl_private const Ray *ray,
+ ccl_private Intersection *isect,
const uint visibility)
{
# ifdef __KERNEL_OPTIX__
@@ -457,6 +703,8 @@ ccl_device_intersect bool scene_intersect_volume(const KernelGlobals *kg,
uint p3 = 0;
uint p4 = visibility;
uint p5 = PRIMITIVE_NONE;
+ uint p6 = ((uint64_t)ray) & 0xFFFFFFFF;
+ uint p7 = (((uint64_t)ray) >> 32) & 0xFFFFFFFF;
uint ray_mask = visibility & 0xFF;
if (0 == ray_mask && (visibility & ~0xFF) != 0) {
@@ -480,7 +728,9 @@ ccl_device_intersect bool scene_intersect_volume(const KernelGlobals *kg,
p2,
p3,
p4,
- p5);
+ p5,
+ p6,
+ p7);
isect->t = __uint_as_float(p0);
isect->u = __uint_as_float(p1);
@@ -490,7 +740,77 @@ ccl_device_intersect bool scene_intersect_volume(const KernelGlobals *kg,
isect->type = p5;
return p5 != PRIMITIVE_NONE;
-# else /* __KERNEL_OPTIX__ */
+# elif defined(__METALRT__)
+
+ if (!scene_intersect_valid(ray)) {
+ return false;
+ }
+# if defined(__KERNEL_DEBUG__)
+ if (is_null_instance_acceleration_structure(metal_ancillaries->accel_struct)) {
+ kernel_assert(!"Invalid metal_ancillaries->accel_struct pointer");
+ return false;
+ }
+
+ if (is_null_intersection_function_table(metal_ancillaries->ift_default)) {
+ kernel_assert(!"Invalid ift_default");
+ return false;
+ }
+# endif
+
+ metal::raytracing::ray r(ray->P, ray->D, 0.0f, ray->t);
+ metalrt_intersector_type metalrt_intersect;
+
+ metalrt_intersect.force_opacity(metal::raytracing::forced_opacity::non_opaque);
+ if (!kernel_data.bvh.have_curves) {
+ metalrt_intersect.assume_geometry_type(metal::raytracing::geometry_type::triangle);
+ }
+
+ MetalRTIntersectionPayload payload;
+ payload.self = ray->self;
+ payload.visibility = visibility;
+
+ typename metalrt_intersector_type::result_type intersection;
+
+ uint ray_mask = visibility & 0xFF;
+ if (0 == ray_mask && (visibility & ~0xFF) != 0) {
+ ray_mask = 0xFF;
+ }
+
+# if defined(__METALRT_MOTION__)
+ payload.time = ray->time;
+ intersection = metalrt_intersect.intersect(r,
+ metal_ancillaries->accel_struct,
+ ray_mask,
+ ray->time,
+ metal_ancillaries->ift_default,
+ payload);
+# else
+ intersection = metalrt_intersect.intersect(
+ r, metal_ancillaries->accel_struct, ray_mask, metal_ancillaries->ift_default, payload);
+# endif
+
+ if (intersection.type == intersection_type::none) {
+ return false;
+ }
+
+ isect->prim = payload.prim;
+ isect->type = payload.type;
+ isect->object = intersection.user_instance_id;
+
+ isect->t = intersection.distance;
+ if (intersection.type == intersection_type::triangle) {
+ isect->u = 1.0f - intersection.triangle_barycentric_coord.y -
+ intersection.triangle_barycentric_coord.x;
+ isect->v = intersection.triangle_barycentric_coord.x;
+ }
+ else {
+ isect->u = payload.u;
+ isect->v = payload.v;
+ }
+
+ return isect->type != PRIMITIVE_NONE;
+
+# else
if (!scene_intersect_valid(ray)) {
return false;
}
@@ -507,9 +827,9 @@ ccl_device_intersect bool scene_intersect_volume(const KernelGlobals *kg,
#endif /* __VOLUME__ */
#ifdef __VOLUME_RECORD_ALL__
-ccl_device_intersect uint scene_intersect_volume_all(const KernelGlobals *kg,
- const Ray *ray,
- Intersection *isect,
+ccl_device_intersect uint scene_intersect_volume_all(KernelGlobals kg,
+ ccl_private const Ray *ray,
+ ccl_private Intersection *isect,
const uint max_hits,
const uint visibility)
{
@@ -523,6 +843,7 @@ ccl_device_intersect uint scene_intersect_volume_all(const KernelGlobals *kg,
ctx.isect_s = isect;
ctx.max_hits = max_hits;
ctx.num_hits = 0;
+ ctx.ray = ray;
IntersectContext rtc_ctx(&ctx);
RTCRay rtc_ray;
kernel_embree_setup_ray(*ray, rtc_ray, visibility);
diff --git a/intern/cycles/kernel/bvh/bvh_embree.h b/intern/cycles/kernel/bvh/bvh_embree.h
deleted file mode 100644
index 092d770dcac..00000000000
--- a/intern/cycles/kernel/bvh/bvh_embree.h
+++ /dev/null
@@ -1,147 +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;
-
- const KernelGlobals *kg;
- RayType type;
-
- /* for shadow rays */
- Intersection *isect_s;
- int max_hits;
- int num_hits;
- float max_t;
- bool opaque_hit;
-
- /* for SSS Rays: */
- LocalIntersection *local_isect;
- int local_object_id;
- uint *lcg_state;
-
- CCLIntersectContext(const KernelGlobals *kg_, RayType type_)
- {
- kg = kg_;
- type = type_;
- max_hits = 1;
- num_hits = 0;
- 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(const KernelGlobals *kg,
- const RTCRay *ray,
- const RTCHit *hit,
- Intersection *isect)
-{
- bool is_hair = hit->geomID & 1;
- isect->u = is_hair ? hit->u : 1.0f - hit->v - hit->u;
- isect->v = is_hair ? hit->v : hit->u;
- isect->t = ray->tfar;
- isect->Ng = make_float3(hit->Ng_x, hit->Ng_y, hit->Ng_z);
- 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 = OBJECT_NONE;
- }
- isect->type = kernel_tex_fetch(__prim_type, isect->prim);
-}
-
-ccl_device_inline void kernel_embree_convert_sss_hit(const KernelGlobals *kg,
- const RTCRay *ray,
- const RTCHit *hit,
- Intersection *isect,
- int local_object_id)
-{
- isect->u = 1.0f - hit->v - hit->u;
- isect->v = hit->u;
- isect->t = ray->tfar;
- isect->Ng = make_float3(hit->Ng_x, hit->Ng_y, hit->Ng_z);
- RTCScene inst_scene = (RTCScene)rtcGetGeometryUserData(
- rtcGetGeometry(kernel_data.bvh.scene, local_object_id * 2));
- isect->prim = hit->primID +
- (intptr_t)rtcGetGeometryUserData(rtcGetGeometry(inst_scene, hit->geomID));
- isect->object = local_object_id;
- isect->type = kernel_tex_fetch(__prim_type, isect->prim);
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/bvh/bvh_local.h b/intern/cycles/kernel/bvh/bvh_local.h
deleted file mode 100644
index 90b9f410b29..00000000000
--- a/intern/cycles/kernel/bvh/bvh_local.h
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * Adapted from code Copyright 2009-2010 NVIDIA Corporation,
- * and code copyright 2009-2012 Intel Corporation
- *
- * Modifications Copyright 2011-2013, Blender Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 BVH_FEATURE(BVH_HAIR)
-# define NODE_INTERSECT bvh_node_intersect
-#else
-# define NODE_INTERSECT bvh_aligned_node_intersect
-#endif
-
-/* This is a template BVH traversal function for finding local intersections
- * around the shading point, for subsurface scattering and bevel. We disable
- * various features for performance, and for instanced objects avoid traversing
- * other parts of the scene.
- *
- * BVH_MOTION: motion blur rendering
- */
-
-#ifndef __KERNEL_GPU__
-ccl_device
-#else
-ccl_device_inline
-#endif
- bool BVH_FUNCTION_FULL_NAME(BVH)(const KernelGlobals *kg,
- const Ray *ray,
- LocalIntersection *local_isect,
- int local_object,
- uint *lcg_state,
- int max_hits)
-{
- /* todo:
- * - test if pushing distance on the stack helps (for non shadow rays)
- * - separate version for shadow rays
- * - likely and unlikely for if() statements
- * - test restrict attribute for pointers
- */
-
- /* traversal stack in CUDA thread-local memory */
- int traversal_stack[BVH_STACK_SIZE];
- traversal_stack[0] = ENTRYPOINT_SENTINEL;
-
- /* traversal variables in registers */
- int stack_ptr = 0;
- int node_addr = kernel_tex_fetch(__object_node, local_object);
-
- /* ray parameters in registers */
- float3 P = ray->P;
- float3 dir = bvh_clamp_direction(ray->D);
- float3 idir = bvh_inverse_direction(dir);
- int object = OBJECT_NONE;
- float isect_t = ray->t;
-
- if (local_isect != NULL) {
- local_isect->num_hits = 0;
- }
- kernel_assert((local_isect == NULL) == (max_hits == 0));
-
- const int object_flag = kernel_tex_fetch(__object_flag, local_object);
- if (!(object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
-#if BVH_FEATURE(BVH_MOTION)
- Transform ob_itfm;
- isect_t *= bvh_instance_motion_push(kg, local_object, ray, &P, &dir, &idir, &ob_itfm);
-#else
- isect_t *= bvh_instance_push(kg, local_object, ray, &P, &dir, &idir);
-#endif
- object = local_object;
- }
-
- /* traversal loop */
- do {
- do {
- /* traverse internal nodes */
- while (node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) {
- int node_addr_child1, traverse_mask;
- float dist[2];
- float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr + 0);
-
- traverse_mask = NODE_INTERSECT(kg,
- P,
-#if BVH_FEATURE(BVH_HAIR)
- dir,
-#endif
- idir,
- isect_t,
- node_addr,
- PATH_RAY_ALL_VISIBILITY,
- dist);
-
- node_addr = __float_as_int(cnodes.z);
- node_addr_child1 = __float_as_int(cnodes.w);
-
- if (traverse_mask == 3) {
- /* Both children were intersected, push the farther one. */
- bool is_closest_child1 = (dist[1] < dist[0]);
- if (is_closest_child1) {
- int tmp = node_addr;
- node_addr = node_addr_child1;
- node_addr_child1 = tmp;
- }
-
- ++stack_ptr;
- kernel_assert(stack_ptr < BVH_STACK_SIZE);
- traversal_stack[stack_ptr] = node_addr_child1;
- }
- else {
- /* One child was intersected. */
- if (traverse_mask == 2) {
- node_addr = node_addr_child1;
- }
- else if (traverse_mask == 0) {
- /* Neither child was intersected. */
- node_addr = traversal_stack[stack_ptr];
- --stack_ptr;
- }
- }
- }
-
- /* if node is leaf, fetch triangle list */
- if (node_addr < 0) {
- float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr - 1));
- int prim_addr = __float_as_int(leaf.x);
-
- const int prim_addr2 = __float_as_int(leaf.y);
- const uint type = __float_as_int(leaf.w);
-
- /* pop */
- node_addr = traversal_stack[stack_ptr];
- --stack_ptr;
-
- /* primitive intersection */
- switch (type & PRIMITIVE_ALL) {
- case PRIMITIVE_TRIANGLE: {
- /* intersect ray against primitive */
- for (; prim_addr < prim_addr2; prim_addr++) {
- kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
- if (triangle_intersect_local(kg,
- local_isect,
- P,
- dir,
- object,
- local_object,
- prim_addr,
- isect_t,
- lcg_state,
- max_hits)) {
- return true;
- }
- }
- break;
- }
-#if BVH_FEATURE(BVH_MOTION)
- case PRIMITIVE_MOTION_TRIANGLE: {
- /* intersect ray against primitive */
- for (; prim_addr < prim_addr2; prim_addr++) {
- kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
- if (motion_triangle_intersect_local(kg,
- local_isect,
- P,
- dir,
- ray->time,
- object,
- local_object,
- prim_addr,
- isect_t,
- lcg_state,
- max_hits)) {
- return true;
- }
- }
- break;
- }
-#endif
- default: {
- break;
- }
- }
- }
- } while (node_addr != ENTRYPOINT_SENTINEL);
- } while (node_addr != ENTRYPOINT_SENTINEL);
-
- return false;
-}
-
-ccl_device_inline bool BVH_FUNCTION_NAME(const KernelGlobals *kg,
- const Ray *ray,
- LocalIntersection *local_isect,
- int local_object,
- uint *lcg_state,
- int max_hits)
-{
- return BVH_FUNCTION_FULL_NAME(BVH)(kg, ray, local_isect, local_object, lcg_state, max_hits);
-}
-
-#undef BVH_FUNCTION_NAME
-#undef BVH_FUNCTION_FEATURES
-#undef NODE_INTERSECT
diff --git a/intern/cycles/kernel/bvh/bvh_nodes.h b/intern/cycles/kernel/bvh/bvh_nodes.h
deleted file mode 100644
index 15cd0f22213..00000000000
--- a/intern/cycles/kernel/bvh/bvh_nodes.h
+++ /dev/null
@@ -1,153 +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.
- */
-
-// TODO(sergey): Look into avoid use of full Transform and use 3x3 matrix and
-// 3-vector which might be faster.
-ccl_device_forceinline Transform bvh_unaligned_node_fetch_space(const KernelGlobals *kg,
- int node_addr,
- int child)
-{
- Transform space;
- const int child_addr = node_addr + child * 3;
- space.x = kernel_tex_fetch(__bvh_nodes, child_addr + 1);
- space.y = kernel_tex_fetch(__bvh_nodes, child_addr + 2);
- space.z = kernel_tex_fetch(__bvh_nodes, child_addr + 3);
- return space;
-}
-
-ccl_device_forceinline int bvh_aligned_node_intersect(const KernelGlobals *kg,
- const float3 P,
- const float3 idir,
- const float t,
- const int node_addr,
- const uint visibility,
- float dist[2])
-{
-
- /* fetch node data */
-#ifdef __VISIBILITY_FLAG__
- float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr + 0);
-#endif
- float4 node0 = kernel_tex_fetch(__bvh_nodes, node_addr + 1);
- float4 node1 = kernel_tex_fetch(__bvh_nodes, node_addr + 2);
- float4 node2 = kernel_tex_fetch(__bvh_nodes, node_addr + 3);
-
- /* intersect ray against child nodes */
- float c0lox = (node0.x - P.x) * idir.x;
- float c0hix = (node0.z - P.x) * idir.x;
- float c0loy = (node1.x - P.y) * idir.y;
- float c0hiy = (node1.z - P.y) * idir.y;
- float c0loz = (node2.x - P.z) * idir.z;
- float c0hiz = (node2.z - P.z) * idir.z;
- float c0min = max4(0.0f, min(c0lox, c0hix), min(c0loy, c0hiy), min(c0loz, c0hiz));
- float c0max = min4(t, max(c0lox, c0hix), max(c0loy, c0hiy), max(c0loz, c0hiz));
-
- float c1lox = (node0.y - P.x) * idir.x;
- float c1hix = (node0.w - P.x) * idir.x;
- float c1loy = (node1.y - P.y) * idir.y;
- float c1hiy = (node1.w - P.y) * idir.y;
- float c1loz = (node2.y - P.z) * idir.z;
- float c1hiz = (node2.w - P.z) * idir.z;
- float c1min = max4(0.0f, min(c1lox, c1hix), min(c1loy, c1hiy), min(c1loz, c1hiz));
- float c1max = min4(t, max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz));
-
- dist[0] = c0min;
- dist[1] = c1min;
-
-#ifdef __VISIBILITY_FLAG__
- /* this visibility test gives a 5% performance hit, how to solve? */
- return (((c0max >= c0min) && (__float_as_uint(cnodes.x) & visibility)) ? 1 : 0) |
- (((c1max >= c1min) && (__float_as_uint(cnodes.y) & visibility)) ? 2 : 0);
-#else
- return ((c0max >= c0min) ? 1 : 0) | ((c1max >= c1min) ? 2 : 0);
-#endif
-}
-
-ccl_device_forceinline bool bvh_unaligned_node_intersect_child(const KernelGlobals *kg,
- const float3 P,
- const float3 dir,
- const float t,
- int node_addr,
- int child,
- float dist[2])
-{
- Transform space = bvh_unaligned_node_fetch_space(kg, node_addr, child);
- float3 aligned_dir = transform_direction(&space, dir);
- float3 aligned_P = transform_point(&space, P);
- float3 nrdir = -bvh_inverse_direction(aligned_dir);
- float3 lower_xyz = aligned_P * nrdir;
- float3 upper_xyz = lower_xyz - nrdir;
- const float near_x = min(lower_xyz.x, upper_xyz.x);
- const float near_y = min(lower_xyz.y, upper_xyz.y);
- const float near_z = min(lower_xyz.z, upper_xyz.z);
- const float far_x = max(lower_xyz.x, upper_xyz.x);
- const float far_y = max(lower_xyz.y, upper_xyz.y);
- const float far_z = max(lower_xyz.z, upper_xyz.z);
- const float tnear = max4(0.0f, near_x, near_y, near_z);
- const float tfar = min4(t, far_x, far_y, far_z);
- *dist = tnear;
- return tnear <= tfar;
-}
-
-ccl_device_forceinline int bvh_unaligned_node_intersect(const KernelGlobals *kg,
- const float3 P,
- const float3 dir,
- const float3 idir,
- const float t,
- const int node_addr,
- const uint visibility,
- float dist[2])
-{
- int mask = 0;
-#ifdef __VISIBILITY_FLAG__
- float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr + 0);
-#endif
- if (bvh_unaligned_node_intersect_child(kg, P, dir, t, node_addr, 0, &dist[0])) {
-#ifdef __VISIBILITY_FLAG__
- if ((__float_as_uint(cnodes.x) & visibility))
-#endif
- {
- mask |= 1;
- }
- }
- if (bvh_unaligned_node_intersect_child(kg, P, dir, t, node_addr, 1, &dist[1])) {
-#ifdef __VISIBILITY_FLAG__
- if ((__float_as_uint(cnodes.y) & visibility))
-#endif
- {
- mask |= 2;
- }
- }
- return mask;
-}
-
-ccl_device_forceinline int bvh_node_intersect(const KernelGlobals *kg,
- const float3 P,
- const float3 dir,
- const float3 idir,
- const float t,
- const int node_addr,
- const uint visibility,
- float dist[2])
-{
- float4 node = kernel_tex_fetch(__bvh_nodes, node_addr);
- if (__float_as_uint(node.x) & PATH_RAY_NODE_UNALIGNED) {
- return bvh_unaligned_node_intersect(kg, P, dir, idir, t, node_addr, visibility, dist);
- }
- else {
- return bvh_aligned_node_intersect(kg, P, idir, t, node_addr, visibility, dist);
- }
-}
diff --git a/intern/cycles/kernel/bvh/bvh_shadow_all.h b/intern/cycles/kernel/bvh/bvh_shadow_all.h
deleted file mode 100644
index 0ae36fccf9b..00000000000
--- a/intern/cycles/kernel/bvh/bvh_shadow_all.h
+++ /dev/null
@@ -1,296 +0,0 @@
-/*
- * Adapted from code Copyright 2009-2010 NVIDIA Corporation,
- * and code copyright 2009-2012 Intel Corporation
- *
- * Modifications Copyright 2011-2013, Blender Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 BVH_FEATURE(BVH_HAIR)
-# define NODE_INTERSECT bvh_node_intersect
-#else
-# define NODE_INTERSECT bvh_aligned_node_intersect
-#endif
-
-/* This is a template BVH traversal function, where various features can be
- * enabled/disabled. This way we can compile optimized versions for each case
- * without new features slowing things down.
- *
- * BVH_HAIR: hair curve rendering
- * BVH_MOTION: motion blur rendering
- */
-
-#ifndef __KERNEL_GPU__
-ccl_device
-#else
-ccl_device_inline
-#endif
- bool BVH_FUNCTION_FULL_NAME(BVH)(const KernelGlobals *kg,
- const Ray *ray,
- Intersection *isect_array,
- const uint visibility,
- const uint max_hits,
- uint *num_hits)
-{
- /* todo:
- * - likely and unlikely for if() statements
- * - test restrict attribute for pointers
- */
-
- /* traversal stack in CUDA thread-local memory */
- int traversal_stack[BVH_STACK_SIZE];
- traversal_stack[0] = ENTRYPOINT_SENTINEL;
-
- /* traversal variables in registers */
- int stack_ptr = 0;
- int node_addr = kernel_data.bvh.root;
-
- /* ray parameters in registers */
- const float tmax = ray->t;
- float3 P = ray->P;
- float3 dir = bvh_clamp_direction(ray->D);
- float3 idir = bvh_inverse_direction(dir);
- int object = OBJECT_NONE;
- float isect_t = tmax;
-
-#if BVH_FEATURE(BVH_MOTION)
- Transform ob_itfm;
-#endif
-
- float t_world_to_instance = 1.0f;
-
- *num_hits = 0;
- Intersection *isect = isect_array;
-
- /* traversal loop */
- do {
- do {
- /* traverse internal nodes */
- while (node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) {
- int node_addr_child1, traverse_mask;
- float dist[2];
- float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr + 0);
-
- traverse_mask = NODE_INTERSECT(kg,
- P,
-#if BVH_FEATURE(BVH_HAIR)
- dir,
-#endif
- idir,
- isect_t,
- node_addr,
- visibility,
- dist);
-
- node_addr = __float_as_int(cnodes.z);
- node_addr_child1 = __float_as_int(cnodes.w);
-
- if (traverse_mask == 3) {
- /* Both children were intersected, push the farther one. */
- bool is_closest_child1 = (dist[1] < dist[0]);
- if (is_closest_child1) {
- int tmp = node_addr;
- node_addr = node_addr_child1;
- node_addr_child1 = tmp;
- }
-
- ++stack_ptr;
- kernel_assert(stack_ptr < BVH_STACK_SIZE);
- traversal_stack[stack_ptr] = node_addr_child1;
- }
- else {
- /* One child was intersected. */
- if (traverse_mask == 2) {
- node_addr = node_addr_child1;
- }
- else if (traverse_mask == 0) {
- /* Neither child was intersected. */
- node_addr = traversal_stack[stack_ptr];
- --stack_ptr;
- }
- }
- }
-
- /* if node is leaf, fetch triangle list */
- if (node_addr < 0) {
- float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr - 1));
- int prim_addr = __float_as_int(leaf.x);
-
- if (prim_addr >= 0) {
- const int prim_addr2 = __float_as_int(leaf.y);
- const uint type = __float_as_int(leaf.w);
- const uint p_type = type & PRIMITIVE_ALL;
-
- /* pop */
- node_addr = traversal_stack[stack_ptr];
- --stack_ptr;
-
- /* primitive intersection */
- while (prim_addr < prim_addr2) {
- kernel_assert((kernel_tex_fetch(__prim_type, prim_addr) & PRIMITIVE_ALL) == p_type);
- bool hit;
-
- /* todo: specialized intersect functions which don't fill in
- * isect unless needed and check SD_HAS_TRANSPARENT_SHADOW?
- * might give a few % performance improvement */
-
- switch (p_type) {
- case PRIMITIVE_TRIANGLE: {
- hit = triangle_intersect(
- kg, isect, P, dir, isect_t, visibility, object, prim_addr);
- break;
- }
-#if BVH_FEATURE(BVH_MOTION)
- case PRIMITIVE_MOTION_TRIANGLE: {
- hit = motion_triangle_intersect(
- kg, isect, P, dir, isect_t, ray->time, visibility, object, prim_addr);
- break;
- }
-#endif
-#if BVH_FEATURE(BVH_HAIR)
- case PRIMITIVE_CURVE_THICK:
- case PRIMITIVE_MOTION_CURVE_THICK:
- case PRIMITIVE_CURVE_RIBBON:
- case PRIMITIVE_MOTION_CURVE_RIBBON: {
- const uint curve_type = kernel_tex_fetch(__prim_type, prim_addr);
- hit = curve_intersect(kg,
- isect,
- P,
- dir,
- isect_t,
- visibility,
- object,
- prim_addr,
- ray->time,
- curve_type);
- break;
- }
-#endif
- default: {
- hit = false;
- break;
- }
- }
-
- /* shadow ray early termination */
- if (hit) {
- /* Convert intersection distance to world space. */
- isect->t /= t_world_to_instance;
-
- /* detect if this surface has a shader with transparent shadows */
-
- /* todo: optimize so primitive visibility flag indicates if
- * the primitive has a transparent shadow shader? */
- const int flags = intersection_get_shader_flags(kg, isect);
-
- if (!(flags & SD_HAS_TRANSPARENT_SHADOW) || max_hits == 0) {
- /* If no transparent shadows, all light is blocked and we can
- * stop immediately. */
- return true;
- }
-
- /* Increase the number of hits, possibly beyond max_hits, we will
- * simply not record those and only keep the max_hits closest. */
- (*num_hits)++;
-
- if (*num_hits >= max_hits) {
- /* If maximum number of hits reached, find the intersection with
- * the largest distance to potentially replace when another hit
- * is found. */
- const int num_recorded_hits = min(max_hits, *num_hits);
- float max_recorded_t = isect_array[0].t;
- int max_recorded_hit = 0;
-
- for (int i = 1; i < num_recorded_hits; i++) {
- if (isect_array[i].t > max_recorded_t) {
- max_recorded_t = isect_array[i].t;
- max_recorded_hit = i;
- }
- }
-
- isect = isect_array + max_recorded_hit;
-
- /* Limit the ray distance and stop counting hits beyond this. */
- isect_t = max_recorded_t * t_world_to_instance;
- }
- else {
- /* Still have space for intersection, use next hit. */
- isect = isect + 1;
- }
- }
-
- prim_addr++;
- }
- }
- else {
- /* instance push */
- object = kernel_tex_fetch(__prim_object, -prim_addr - 1);
-
-#if BVH_FEATURE(BVH_MOTION)
- t_world_to_instance = bvh_instance_motion_push(
- kg, object, ray, &P, &dir, &idir, &ob_itfm);
-#else
- t_world_to_instance = bvh_instance_push(kg, object, ray, &P, &dir, &idir);
-#endif
-
- /* Convert intersection to object space. */
- isect_t *= t_world_to_instance;
-
- ++stack_ptr;
- kernel_assert(stack_ptr < BVH_STACK_SIZE);
- traversal_stack[stack_ptr] = ENTRYPOINT_SENTINEL;
-
- node_addr = kernel_tex_fetch(__object_node, object);
- }
- }
- } while (node_addr != ENTRYPOINT_SENTINEL);
-
- if (stack_ptr >= 0) {
- kernel_assert(object != OBJECT_NONE);
-
- /* Instance pop. */
-#if BVH_FEATURE(BVH_MOTION)
- bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir, FLT_MAX, &ob_itfm);
-#else
- bvh_instance_pop(kg, object, ray, &P, &dir, &idir, FLT_MAX);
-#endif
-
- /* Restore world space ray length. If max number of hits exceeded this
- * distance is reduced to recorded only the closest hits. If not use
- * the original ray length. */
- isect_t = (max_hits && *num_hits > max_hits) ? isect->t : tmax;
-
- object = OBJECT_NONE;
- t_world_to_instance = 1.0f;
- node_addr = traversal_stack[stack_ptr];
- --stack_ptr;
- }
- } while (node_addr != ENTRYPOINT_SENTINEL);
-
- return false;
-}
-
-ccl_device_inline bool BVH_FUNCTION_NAME(const KernelGlobals *kg,
- const Ray *ray,
- Intersection *isect_array,
- const uint visibility,
- const uint max_hits,
- uint *num_hits)
-{
- return BVH_FUNCTION_FULL_NAME(BVH)(kg, ray, isect_array, visibility, max_hits, num_hits);
-}
-
-#undef BVH_FUNCTION_NAME
-#undef BVH_FUNCTION_FEATURES
-#undef NODE_INTERSECT
diff --git a/intern/cycles/kernel/bvh/bvh_traversal.h b/intern/cycles/kernel/bvh/bvh_traversal.h
deleted file mode 100644
index a26d8c514f3..00000000000
--- a/intern/cycles/kernel/bvh/bvh_traversal.h
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * Adapted from code Copyright 2009-2010 NVIDIA Corporation,
- * and code copyright 2009-2012 Intel Corporation
- *
- * Modifications Copyright 2011-2013, Blender Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 BVH_FEATURE(BVH_HAIR)
-# define NODE_INTERSECT bvh_node_intersect
-#else
-# define NODE_INTERSECT bvh_aligned_node_intersect
-#endif
-
-/* This is a template BVH traversal function, where various features can be
- * enabled/disabled. This way we can compile optimized versions for each case
- * without new features slowing things down.
- *
- * BVH_HAIR: hair curve rendering
- * BVH_MOTION: motion blur rendering
- */
-
-ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(const KernelGlobals *kg,
- const Ray *ray,
- Intersection *isect,
- const uint visibility)
-{
- /* todo:
- * - test if pushing distance on the stack helps (for non shadow rays)
- * - separate version for shadow rays
- * - likely and unlikely for if() statements
- * - test restrict attribute for pointers
- */
-
- /* traversal stack in CUDA thread-local memory */
- int traversal_stack[BVH_STACK_SIZE];
- traversal_stack[0] = ENTRYPOINT_SENTINEL;
-
- /* traversal variables in registers */
- int stack_ptr = 0;
- int node_addr = kernel_data.bvh.root;
-
- /* ray parameters in registers */
- float3 P = ray->P;
- float3 dir = bvh_clamp_direction(ray->D);
- float3 idir = bvh_inverse_direction(dir);
- int object = OBJECT_NONE;
-
-#if BVH_FEATURE(BVH_MOTION)
- Transform ob_itfm;
-#endif
-
- isect->t = ray->t;
- isect->u = 0.0f;
- isect->v = 0.0f;
- isect->prim = PRIM_NONE;
- isect->object = OBJECT_NONE;
-
- /* traversal loop */
- do {
- do {
- /* traverse internal nodes */
- while (node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) {
- int node_addr_child1, traverse_mask;
- float dist[2];
- float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr + 0);
-
- {
- traverse_mask = NODE_INTERSECT(kg,
- P,
-#if BVH_FEATURE(BVH_HAIR)
- dir,
-#endif
- idir,
- isect->t,
- node_addr,
- visibility,
- dist);
- }
-
- node_addr = __float_as_int(cnodes.z);
- node_addr_child1 = __float_as_int(cnodes.w);
-
- if (traverse_mask == 3) {
- /* Both children were intersected, push the farther one. */
- bool is_closest_child1 = (dist[1] < dist[0]);
- if (is_closest_child1) {
- int tmp = node_addr;
- node_addr = node_addr_child1;
- node_addr_child1 = tmp;
- }
-
- ++stack_ptr;
- kernel_assert(stack_ptr < BVH_STACK_SIZE);
- traversal_stack[stack_ptr] = node_addr_child1;
- }
- else {
- /* One child was intersected. */
- if (traverse_mask == 2) {
- node_addr = node_addr_child1;
- }
- else if (traverse_mask == 0) {
- /* Neither child was intersected. */
- node_addr = traversal_stack[stack_ptr];
- --stack_ptr;
- }
- }
- }
-
- /* if node is leaf, fetch triangle list */
- if (node_addr < 0) {
- float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr - 1));
- int prim_addr = __float_as_int(leaf.x);
-
- if (prim_addr >= 0) {
- const int prim_addr2 = __float_as_int(leaf.y);
- const uint type = __float_as_int(leaf.w);
-
- /* pop */
- node_addr = traversal_stack[stack_ptr];
- --stack_ptr;
-
- /* primitive intersection */
- switch (type & PRIMITIVE_ALL) {
- case PRIMITIVE_TRIANGLE: {
- for (; prim_addr < prim_addr2; prim_addr++) {
- kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
- if (triangle_intersect(
- kg, isect, P, dir, isect->t, visibility, object, prim_addr)) {
- /* shadow ray early termination */
- if (visibility & PATH_RAY_SHADOW_OPAQUE)
- return true;
- }
- }
- break;
- }
-#if BVH_FEATURE(BVH_MOTION)
- case PRIMITIVE_MOTION_TRIANGLE: {
- for (; prim_addr < prim_addr2; prim_addr++) {
- kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
- if (motion_triangle_intersect(
- kg, isect, P, dir, isect->t, ray->time, visibility, object, prim_addr)) {
- /* shadow ray early termination */
- if (visibility & PATH_RAY_SHADOW_OPAQUE)
- return true;
- }
- }
- break;
- }
-#endif /* BVH_FEATURE(BVH_MOTION) */
-#if BVH_FEATURE(BVH_HAIR)
- case PRIMITIVE_CURVE_THICK:
- case PRIMITIVE_MOTION_CURVE_THICK:
- case PRIMITIVE_CURVE_RIBBON:
- case PRIMITIVE_MOTION_CURVE_RIBBON: {
- for (; prim_addr < prim_addr2; prim_addr++) {
- const uint curve_type = kernel_tex_fetch(__prim_type, prim_addr);
- kernel_assert((curve_type & PRIMITIVE_ALL) == (type & PRIMITIVE_ALL));
- const bool hit = curve_intersect(kg,
- isect,
- P,
- dir,
- isect->t,
- visibility,
- object,
- prim_addr,
- ray->time,
- curve_type);
- if (hit) {
- /* shadow ray early termination */
- if (visibility & PATH_RAY_SHADOW_OPAQUE)
- return true;
- }
- }
- break;
- }
-#endif /* BVH_FEATURE(BVH_HAIR) */
- }
- }
- else {
- /* instance push */
- object = kernel_tex_fetch(__prim_object, -prim_addr - 1);
-
-#if BVH_FEATURE(BVH_MOTION)
- isect->t *= bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &ob_itfm);
-#else
- isect->t *= bvh_instance_push(kg, object, ray, &P, &dir, &idir);
-#endif
-
- ++stack_ptr;
- kernel_assert(stack_ptr < BVH_STACK_SIZE);
- traversal_stack[stack_ptr] = ENTRYPOINT_SENTINEL;
-
- node_addr = kernel_tex_fetch(__object_node, object);
- }
- }
- } while (node_addr != ENTRYPOINT_SENTINEL);
-
- if (stack_ptr >= 0) {
- kernel_assert(object != OBJECT_NONE);
-
- /* instance pop */
-#if BVH_FEATURE(BVH_MOTION)
- isect->t = bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir, isect->t, &ob_itfm);
-#else
- isect->t = bvh_instance_pop(kg, object, ray, &P, &dir, &idir, isect->t);
-#endif
-
- object = OBJECT_NONE;
- node_addr = traversal_stack[stack_ptr];
- --stack_ptr;
- }
- } while (node_addr != ENTRYPOINT_SENTINEL);
-
- return (isect->prim != PRIM_NONE);
-}
-
-ccl_device_inline bool BVH_FUNCTION_NAME(const KernelGlobals *kg,
- const Ray *ray,
- Intersection *isect,
- const uint visibility)
-{
- return BVH_FUNCTION_FULL_NAME(BVH)(kg, ray, isect, visibility);
-}
-
-#undef BVH_FUNCTION_NAME
-#undef BVH_FUNCTION_FEATURES
-#undef NODE_INTERSECT
diff --git a/intern/cycles/kernel/bvh/bvh_types.h b/intern/cycles/kernel/bvh/bvh_types.h
deleted file mode 100644
index 6039e707fc3..00000000000
--- a/intern/cycles/kernel/bvh/bvh_types.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.
- */
-
-#pragma once
-
-CCL_NAMESPACE_BEGIN
-
-/* Don't inline intersect functions on GPU, this is faster */
-#ifdef __KERNEL_GPU__
-# define ccl_device_intersect ccl_device_forceinline
-#else
-# define ccl_device_intersect ccl_device_inline
-#endif
-
-/* bottom-most stack entry, indicating the end of traversal */
-#define ENTRYPOINT_SENTINEL 0x76543210
-
-/* 64 object BVH + 64 mesh BVH + 64 object node splitting */
-#define BVH_STACK_SIZE 192
-/* BVH intersection function variations */
-
-#define BVH_MOTION 1
-#define BVH_HAIR 2
-
-#define BVH_NAME_JOIN(x, y) x##_##y
-#define BVH_NAME_EVAL(x, y) BVH_NAME_JOIN(x, y)
-#define BVH_FUNCTION_FULL_NAME(prefix) BVH_NAME_EVAL(prefix, BVH_FUNCTION_NAME)
-
-#define BVH_FEATURE(f) (((BVH_FUNCTION_FEATURES) & (f)) != 0)
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/bvh/bvh_util.h b/intern/cycles/kernel/bvh/bvh_util.h
deleted file mode 100644
index 21384457b16..00000000000
--- a/intern/cycles/kernel/bvh/bvh_util.h
+++ /dev/null
@@ -1,186 +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
-
-/* Ray offset to avoid self intersection.
- *
- * This function should be used to compute a modified ray start position for
- * rays leaving from a surface. */
-
-ccl_device_inline float3 ray_offset(float3 P, float3 Ng)
-{
-#ifdef __INTERSECTION_REFINE__
- const float epsilon_f = 1e-5f;
- /* ideally this should match epsilon_f, but instancing and motion blur
- * precision makes it problematic */
- const float epsilon_test = 1.0f;
- const int epsilon_i = 32;
-
- float3 res;
-
- /* x component */
- if (fabsf(P.x) < epsilon_test) {
- res.x = P.x + Ng.x * epsilon_f;
- }
- else {
- uint ix = __float_as_uint(P.x);
- ix += ((ix ^ __float_as_uint(Ng.x)) >> 31) ? -epsilon_i : epsilon_i;
- res.x = __uint_as_float(ix);
- }
-
- /* y component */
- if (fabsf(P.y) < epsilon_test) {
- res.y = P.y + Ng.y * epsilon_f;
- }
- else {
- uint iy = __float_as_uint(P.y);
- iy += ((iy ^ __float_as_uint(Ng.y)) >> 31) ? -epsilon_i : epsilon_i;
- res.y = __uint_as_float(iy);
- }
-
- /* z component */
- if (fabsf(P.z) < epsilon_test) {
- res.z = P.z + Ng.z * epsilon_f;
- }
- else {
- uint iz = __float_as_uint(P.z);
- iz += ((iz ^ __float_as_uint(Ng.z)) >> 31) ? -epsilon_i : epsilon_i;
- res.z = __uint_as_float(iz);
- }
-
- return res;
-#else
- const float epsilon_f = 1e-4f;
- return P + epsilon_f * Ng;
-#endif
-}
-
-#if defined(__VOLUME_RECORD_ALL__) || (defined(__SHADOW_RECORD_ALL__) && defined(__KERNEL_CPU__))
-/* ToDo: Move to another file? */
-ccl_device int intersections_compare(const void *a, const void *b)
-{
- const Intersection *isect_a = (const Intersection *)a;
- const Intersection *isect_b = (const Intersection *)b;
-
- if (isect_a->t < isect_b->t)
- return -1;
- else if (isect_a->t > isect_b->t)
- return 1;
- else
- return 0;
-}
-#endif
-
-#if defined(__SHADOW_RECORD_ALL__)
-ccl_device_inline void sort_intersections(Intersection *hits, uint num_hits)
-{
- kernel_assert(num_hits > 0);
-
-# ifdef __KERNEL_GPU__
- /* Use bubble sort which has more friendly memory pattern on GPU. */
- bool swapped;
- do {
- swapped = false;
- for (int j = 0; j < num_hits - 1; ++j) {
- if (hits[j].t > hits[j + 1].t) {
- struct Intersection tmp = hits[j];
- hits[j] = hits[j + 1];
- hits[j + 1] = tmp;
- swapped = true;
- }
- }
- --num_hits;
- } while (swapped);
-# else
- qsort(hits, num_hits, sizeof(Intersection), intersections_compare);
-# endif
-}
-#endif /* __SHADOW_RECORD_ALL__ | __VOLUME_RECORD_ALL__ */
-
-/* Utility to quickly get flags from an intersection. */
-
-ccl_device_forceinline int intersection_get_shader_flags(const KernelGlobals *ccl_restrict kg,
- const Intersection *ccl_restrict isect)
-{
- const int prim = kernel_tex_fetch(__prim_index, isect->prim);
- int shader = 0;
-
-#ifdef __HAIR__
- if (kernel_tex_fetch(__prim_type, isect->prim) & PRIMITIVE_ALL_TRIANGLE)
-#endif
- {
- shader = kernel_tex_fetch(__tri_shader, prim);
- }
-#ifdef __HAIR__
- else {
- float4 str = kernel_tex_fetch(__curves, prim);
- shader = __float_as_int(str.z);
- }
-#endif
-
- return kernel_tex_fetch(__shaders, (shader & SHADER_MASK)).flags;
-}
-
-ccl_device_forceinline int intersection_get_shader_from_isect_prim(
- const KernelGlobals *ccl_restrict kg, const int isect_prim)
-{
- const int prim = kernel_tex_fetch(__prim_index, isect_prim);
- int shader = 0;
-
-#ifdef __HAIR__
- if (kernel_tex_fetch(__prim_type, isect_prim) & PRIMITIVE_ALL_TRIANGLE)
-#endif
- {
- shader = kernel_tex_fetch(__tri_shader, prim);
- }
-#ifdef __HAIR__
- else {
- float4 str = kernel_tex_fetch(__curves, prim);
- shader = __float_as_int(str.z);
- }
-#endif
-
- return shader & SHADER_MASK;
-}
-
-ccl_device_forceinline int intersection_get_shader(const KernelGlobals *ccl_restrict kg,
- const Intersection *ccl_restrict isect)
-{
- return intersection_get_shader_from_isect_prim(kg, isect->prim);
-}
-
-ccl_device_forceinline int intersection_get_object(const KernelGlobals *ccl_restrict kg,
- const Intersection *ccl_restrict isect)
-{
- if (isect->object != OBJECT_NONE) {
- return isect->object;
- }
-
- return kernel_tex_fetch(__prim_object, isect->prim);
-}
-
-ccl_device_forceinline int intersection_get_object_flags(const KernelGlobals *ccl_restrict kg,
- const Intersection *ccl_restrict isect)
-{
- const int object = intersection_get_object(kg, isect);
-
- return kernel_tex_fetch(__object_flag, object);
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/bvh/bvh_volume.h b/intern/cycles/kernel/bvh/bvh_volume.h
deleted file mode 100644
index 0411d9c522d..00000000000
--- a/intern/cycles/kernel/bvh/bvh_volume.h
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * Adapted from code Copyright 2009-2010 NVIDIA Corporation,
- * and code copyright 2009-2012 Intel Corporation
- *
- * Modifications 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.
- */
-
-#if BVH_FEATURE(BVH_HAIR)
-# define NODE_INTERSECT bvh_node_intersect
-#else
-# define NODE_INTERSECT bvh_aligned_node_intersect
-#endif
-
-/* This is a template BVH traversal function for volumes, where
- * various features can be enabled/disabled. This way we can compile optimized
- * versions for each case without new features slowing things down.
- *
- * BVH_MOTION: motion blur rendering
- */
-
-#ifndef __KERNEL_GPU__
-ccl_device
-#else
-ccl_device_inline
-#endif
- bool BVH_FUNCTION_FULL_NAME(BVH)(const KernelGlobals *kg,
- const Ray *ray,
- Intersection *isect,
- const uint visibility)
-{
- /* todo:
- * - test if pushing distance on the stack helps (for non shadow rays)
- * - separate version for shadow rays
- * - likely and unlikely for if() statements
- * - test restrict attribute for pointers
- */
-
- /* traversal stack in CUDA thread-local memory */
- int traversal_stack[BVH_STACK_SIZE];
- traversal_stack[0] = ENTRYPOINT_SENTINEL;
-
- /* traversal variables in registers */
- int stack_ptr = 0;
- int node_addr = kernel_data.bvh.root;
-
- /* ray parameters in registers */
- float3 P = ray->P;
- float3 dir = bvh_clamp_direction(ray->D);
- float3 idir = bvh_inverse_direction(dir);
- int object = OBJECT_NONE;
-
-#if BVH_FEATURE(BVH_MOTION)
- Transform ob_itfm;
-#endif
-
- isect->t = ray->t;
- isect->u = 0.0f;
- isect->v = 0.0f;
- isect->prim = PRIM_NONE;
- isect->object = OBJECT_NONE;
-
- /* traversal loop */
- do {
- do {
- /* traverse internal nodes */
- while (node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) {
- int node_addr_child1, traverse_mask;
- float dist[2];
- float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr + 0);
-
- traverse_mask = NODE_INTERSECT(kg,
- P,
-#if BVH_FEATURE(BVH_HAIR)
- dir,
-#endif
- idir,
- isect->t,
- node_addr,
- visibility,
- dist);
-
- node_addr = __float_as_int(cnodes.z);
- node_addr_child1 = __float_as_int(cnodes.w);
-
- if (traverse_mask == 3) {
- /* Both children were intersected, push the farther one. */
- bool is_closest_child1 = (dist[1] < dist[0]);
- if (is_closest_child1) {
- int tmp = node_addr;
- node_addr = node_addr_child1;
- node_addr_child1 = tmp;
- }
-
- ++stack_ptr;
- kernel_assert(stack_ptr < BVH_STACK_SIZE);
- traversal_stack[stack_ptr] = node_addr_child1;
- }
- else {
- /* One child was intersected. */
- if (traverse_mask == 2) {
- node_addr = node_addr_child1;
- }
- else if (traverse_mask == 0) {
- /* Neither child was intersected. */
- node_addr = traversal_stack[stack_ptr];
- --stack_ptr;
- }
- }
- }
-
- /* if node is leaf, fetch triangle list */
- if (node_addr < 0) {
- float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr - 1));
- int prim_addr = __float_as_int(leaf.x);
-
- if (prim_addr >= 0) {
- const int prim_addr2 = __float_as_int(leaf.y);
- const uint type = __float_as_int(leaf.w);
-
- /* pop */
- node_addr = traversal_stack[stack_ptr];
- --stack_ptr;
-
- /* primitive intersection */
- switch (type & PRIMITIVE_ALL) {
- case PRIMITIVE_TRIANGLE: {
- /* intersect ray against primitive */
- for (; prim_addr < prim_addr2; prim_addr++) {
- kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
- /* only primitives from volume object */
- uint tri_object = (object == OBJECT_NONE) ?
- kernel_tex_fetch(__prim_object, prim_addr) :
- object;
- int object_flag = kernel_tex_fetch(__object_flag, tri_object);
- if ((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
- continue;
- }
- triangle_intersect(kg, isect, P, dir, isect->t, visibility, object, prim_addr);
- }
- break;
- }
-#if BVH_FEATURE(BVH_MOTION)
- case PRIMITIVE_MOTION_TRIANGLE: {
- /* intersect ray against primitive */
- for (; prim_addr < prim_addr2; prim_addr++) {
- kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
- /* only primitives from volume object */
- uint tri_object = (object == OBJECT_NONE) ?
- kernel_tex_fetch(__prim_object, prim_addr) :
- object;
- int object_flag = kernel_tex_fetch(__object_flag, tri_object);
- if ((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
- continue;
- }
- motion_triangle_intersect(
- kg, isect, P, dir, isect->t, ray->time, visibility, object, prim_addr);
- }
- break;
- }
-#endif
- default: {
- break;
- }
- }
- }
- else {
- /* instance push */
- object = kernel_tex_fetch(__prim_object, -prim_addr - 1);
- int object_flag = kernel_tex_fetch(__object_flag, object);
- if (object_flag & SD_OBJECT_HAS_VOLUME) {
-#if BVH_FEATURE(BVH_MOTION)
- isect->t *= bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &ob_itfm);
-#else
- isect->t *= bvh_instance_push(kg, object, ray, &P, &dir, &idir);
-#endif
-
- ++stack_ptr;
- kernel_assert(stack_ptr < BVH_STACK_SIZE);
- traversal_stack[stack_ptr] = ENTRYPOINT_SENTINEL;
-
- node_addr = kernel_tex_fetch(__object_node, object);
- }
- else {
- /* pop */
- object = OBJECT_NONE;
- node_addr = traversal_stack[stack_ptr];
- --stack_ptr;
- }
- }
- }
- } while (node_addr != ENTRYPOINT_SENTINEL);
-
- if (stack_ptr >= 0) {
- kernel_assert(object != OBJECT_NONE);
-
- /* instance pop */
-#if BVH_FEATURE(BVH_MOTION)
- isect->t = bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir, isect->t, &ob_itfm);
-#else
- isect->t = bvh_instance_pop(kg, object, ray, &P, &dir, &idir, isect->t);
-#endif
-
- object = OBJECT_NONE;
- node_addr = traversal_stack[stack_ptr];
- --stack_ptr;
- }
- } while (node_addr != ENTRYPOINT_SENTINEL);
-
- return (isect->prim != PRIM_NONE);
-}
-
-ccl_device_inline bool BVH_FUNCTION_NAME(const KernelGlobals *kg,
- const Ray *ray,
- Intersection *isect,
- const uint visibility)
-{
- return BVH_FUNCTION_FULL_NAME(BVH)(kg, ray, isect, visibility);
-}
-
-#undef BVH_FUNCTION_NAME
-#undef BVH_FUNCTION_FEATURES
-#undef NODE_INTERSECT
diff --git a/intern/cycles/kernel/bvh/bvh_volume_all.h b/intern/cycles/kernel/bvh/bvh_volume_all.h
deleted file mode 100644
index 4874270f15d..00000000000
--- a/intern/cycles/kernel/bvh/bvh_volume_all.h
+++ /dev/null
@@ -1,303 +0,0 @@
-/*
- * Adapted from code Copyright 2009-2010 NVIDIA Corporation,
- * and code copyright 2009-2012 Intel Corporation
- *
- * Modifications 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.
- */
-
-#if BVH_FEATURE(BVH_HAIR)
-# define NODE_INTERSECT bvh_node_intersect
-#else
-# define NODE_INTERSECT bvh_aligned_node_intersect
-#endif
-
-/* This is a template BVH traversal function for volumes, where
- * various features can be enabled/disabled. This way we can compile optimized
- * versions for each case without new features slowing things down.
- *
- * BVH_MOTION: motion blur rendering
- */
-
-#ifndef __KERNEL_GPU__
-ccl_device
-#else
-ccl_device_inline
-#endif
- uint BVH_FUNCTION_FULL_NAME(BVH)(const KernelGlobals *kg,
- const Ray *ray,
- Intersection *isect_array,
- const uint max_hits,
- const uint visibility)
-{
- /* todo:
- * - test if pushing distance on the stack helps (for non shadow rays)
- * - separate version for shadow rays
- * - likely and unlikely for if() statements
- * - test restrict attribute for pointers
- */
-
- /* traversal stack in CUDA thread-local memory */
- int traversal_stack[BVH_STACK_SIZE];
- traversal_stack[0] = ENTRYPOINT_SENTINEL;
-
- /* traversal variables in registers */
- int stack_ptr = 0;
- int node_addr = kernel_data.bvh.root;
-
- /* ray parameters in registers */
- const float tmax = ray->t;
- float3 P = ray->P;
- float3 dir = bvh_clamp_direction(ray->D);
- float3 idir = bvh_inverse_direction(dir);
- int object = OBJECT_NONE;
- float isect_t = tmax;
-
-#if BVH_FEATURE(BVH_MOTION)
- Transform ob_itfm;
-#endif
-
- int num_hits_in_instance = 0;
-
- uint num_hits = 0;
- isect_array->t = tmax;
-
- /* traversal loop */
- do {
- do {
- /* traverse internal nodes */
- while (node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) {
- int node_addr_child1, traverse_mask;
- float dist[2];
- float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr + 0);
-
- traverse_mask = NODE_INTERSECT(kg,
- P,
-#if BVH_FEATURE(BVH_HAIR)
- dir,
-#endif
- idir,
- isect_t,
- node_addr,
- visibility,
- dist);
-
- node_addr = __float_as_int(cnodes.z);
- node_addr_child1 = __float_as_int(cnodes.w);
-
- if (traverse_mask == 3) {
- /* Both children were intersected, push the farther one. */
- bool is_closest_child1 = (dist[1] < dist[0]);
- if (is_closest_child1) {
- int tmp = node_addr;
- node_addr = node_addr_child1;
- node_addr_child1 = tmp;
- }
-
- ++stack_ptr;
- kernel_assert(stack_ptr < BVH_STACK_SIZE);
- traversal_stack[stack_ptr] = node_addr_child1;
- }
- else {
- /* One child was intersected. */
- if (traverse_mask == 2) {
- node_addr = node_addr_child1;
- }
- else if (traverse_mask == 0) {
- /* Neither child was intersected. */
- node_addr = traversal_stack[stack_ptr];
- --stack_ptr;
- }
- }
- }
-
- /* if node is leaf, fetch triangle list */
- if (node_addr < 0) {
- float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr - 1));
- int prim_addr = __float_as_int(leaf.x);
-
- if (prim_addr >= 0) {
- const int prim_addr2 = __float_as_int(leaf.y);
- const uint type = __float_as_int(leaf.w);
- bool hit;
-
- /* pop */
- node_addr = traversal_stack[stack_ptr];
- --stack_ptr;
-
- /* primitive intersection */
- switch (type & PRIMITIVE_ALL) {
- case PRIMITIVE_TRIANGLE: {
- /* intersect ray against primitive */
- for (; prim_addr < prim_addr2; prim_addr++) {
- kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
- /* only primitives from volume object */
- uint tri_object = (object == OBJECT_NONE) ?
- kernel_tex_fetch(__prim_object, prim_addr) :
- object;
- int object_flag = kernel_tex_fetch(__object_flag, tri_object);
- if ((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
- continue;
- }
- hit = triangle_intersect(
- kg, isect_array, P, dir, isect_t, visibility, object, prim_addr);
- if (hit) {
- /* Move on to next entry in intersections array. */
- isect_array++;
- num_hits++;
- num_hits_in_instance++;
- isect_array->t = isect_t;
- if (num_hits == max_hits) {
- if (object != OBJECT_NONE) {
-#if BVH_FEATURE(BVH_MOTION)
- float t_fac = 1.0f / len(transform_direction(&ob_itfm, dir));
-#else
- Transform itfm = object_fetch_transform(
- kg, object, OBJECT_INVERSE_TRANSFORM);
- float t_fac = 1.0f / len(transform_direction(&itfm, dir));
-#endif
- for (int i = 0; i < num_hits_in_instance; i++) {
- (isect_array - i - 1)->t *= t_fac;
- }
- }
- return num_hits;
- }
- }
- }
- break;
- }
-#if BVH_FEATURE(BVH_MOTION)
- case PRIMITIVE_MOTION_TRIANGLE: {
- /* intersect ray against primitive */
- for (; prim_addr < prim_addr2; prim_addr++) {
- kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
- /* only primitives from volume object */
- uint tri_object = (object == OBJECT_NONE) ?
- kernel_tex_fetch(__prim_object, prim_addr) :
- object;
- int object_flag = kernel_tex_fetch(__object_flag, tri_object);
- if ((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
- continue;
- }
- hit = motion_triangle_intersect(
- kg, isect_array, P, dir, isect_t, ray->time, visibility, object, prim_addr);
- if (hit) {
- /* Move on to next entry in intersections array. */
- isect_array++;
- num_hits++;
- num_hits_in_instance++;
- isect_array->t = isect_t;
- if (num_hits == max_hits) {
- if (object != OBJECT_NONE) {
-# if BVH_FEATURE(BVH_MOTION)
- float t_fac = 1.0f / len(transform_direction(&ob_itfm, dir));
-# else
- Transform itfm = object_fetch_transform(
- kg, object, OBJECT_INVERSE_TRANSFORM);
- float t_fac = 1.0f / len(transform_direction(&itfm, dir));
-# endif
- for (int i = 0; i < num_hits_in_instance; i++) {
- (isect_array - i - 1)->t *= t_fac;
- }
- }
- return num_hits;
- }
- }
- }
- break;
- }
-#endif /* BVH_MOTION */
- default: {
- break;
- }
- }
- }
- else {
- /* instance push */
- object = kernel_tex_fetch(__prim_object, -prim_addr - 1);
- int object_flag = kernel_tex_fetch(__object_flag, object);
- if (object_flag & SD_OBJECT_HAS_VOLUME) {
-#if BVH_FEATURE(BVH_MOTION)
- isect_t *= bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &ob_itfm);
-#else
- isect_t *= bvh_instance_push(kg, object, ray, &P, &dir, &idir);
-#endif
-
- num_hits_in_instance = 0;
- isect_array->t = isect_t;
-
- ++stack_ptr;
- kernel_assert(stack_ptr < BVH_STACK_SIZE);
- traversal_stack[stack_ptr] = ENTRYPOINT_SENTINEL;
-
- node_addr = kernel_tex_fetch(__object_node, object);
- }
- else {
- /* pop */
- object = OBJECT_NONE;
- node_addr = traversal_stack[stack_ptr];
- --stack_ptr;
- }
- }
- }
- } while (node_addr != ENTRYPOINT_SENTINEL);
-
- if (stack_ptr >= 0) {
- kernel_assert(object != OBJECT_NONE);
-
- /* Instance pop. */
- if (num_hits_in_instance) {
- float t_fac;
-#if BVH_FEATURE(BVH_MOTION)
- bvh_instance_motion_pop_factor(kg, object, ray, &P, &dir, &idir, &t_fac, &ob_itfm);
-#else
- bvh_instance_pop_factor(kg, object, ray, &P, &dir, &idir, &t_fac);
-#endif
- /* Scale isect->t to adjust for instancing. */
- for (int i = 0; i < num_hits_in_instance; i++) {
- (isect_array - i - 1)->t *= t_fac;
- }
- }
- else {
-#if BVH_FEATURE(BVH_MOTION)
- bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir, FLT_MAX, &ob_itfm);
-#else
- bvh_instance_pop(kg, object, ray, &P, &dir, &idir, FLT_MAX);
-#endif
- }
-
- isect_t = tmax;
- isect_array->t = isect_t;
-
- object = OBJECT_NONE;
- node_addr = traversal_stack[stack_ptr];
- --stack_ptr;
- }
- } while (node_addr != ENTRYPOINT_SENTINEL);
-
- return num_hits;
-}
-
-ccl_device_inline uint BVH_FUNCTION_NAME(const KernelGlobals *kg,
- const Ray *ray,
- Intersection *isect_array,
- const uint max_hits,
- const uint visibility)
-{
- return BVH_FUNCTION_FULL_NAME(BVH)(kg, ray, isect_array, max_hits, visibility);
-}
-
-#undef BVH_FUNCTION_NAME
-#undef BVH_FUNCTION_FEATURES
-#undef NODE_INTERSECT
diff --git a/intern/cycles/kernel/bvh/embree.h b/intern/cycles/kernel/bvh/embree.h
new file mode 100644
index 00000000000..19c4b9f6f3d
--- /dev/null
+++ b/intern/cycles/kernel/bvh/embree.h
@@ -0,0 +1,189 @@
+/*
+ * 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 "kernel/bvh/util.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 avoiding self intersections */
+ const Ray *ray;
+
+ /* 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_;
+ ray = NULL;
+ 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.instID[0] = RTC_INVALID_GEOMETRY_ID;
+}
+
+ccl_device_inline bool kernel_embree_is_self_intersection(const KernelGlobals kg,
+ const RTCHit *hit,
+ const Ray *ray)
+{
+ bool status = false;
+ if (hit->instID[0] != RTC_INVALID_GEOMETRY_ID) {
+ const int oID = hit->instID[0] / 2;
+ if ((ray->self.object == oID) || (ray->self.light_object == oID)) {
+ RTCScene inst_scene = (RTCScene)rtcGetGeometryUserData(
+ rtcGetGeometry(kernel_data.bvh.scene, hit->instID[0]));
+ const int pID = hit->primID +
+ (intptr_t)rtcGetGeometryUserData(rtcGetGeometry(inst_scene, hit->geomID));
+ status = intersection_skip_self_shadow(ray->self, oID, pID);
+ }
+ }
+ else {
+ const int oID = hit->geomID / 2;
+ if ((ray->self.object == oID) || (ray->self.light_object == oID)) {
+ const int pID = hit->primID + (intptr_t)rtcGetGeometryUserData(
+ rtcGetGeometry(kernel_data.bvh.scene, hit->geomID));
+ status = intersection_skip_self_shadow(ray->self, oID, pID);
+ }
+ }
+
+ return status;
+}
+
+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/local.h b/intern/cycles/kernel/bvh/local.h
new file mode 100644
index 00000000000..4ef6deef98d
--- /dev/null
+++ b/intern/cycles/kernel/bvh/local.h
@@ -0,0 +1,241 @@
+/*
+ * Adapted from code Copyright 2009-2010 NVIDIA Corporation,
+ * and code copyright 2009-2012 Intel Corporation
+ *
+ * Modifications Copyright 2011-2013, Blender Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 BVH_FEATURE(BVH_HAIR)
+# define NODE_INTERSECT bvh_node_intersect
+#else
+# define NODE_INTERSECT bvh_aligned_node_intersect
+#endif
+
+/* This is a template BVH traversal function for finding local intersections
+ * around the shading point, for subsurface scattering and bevel. We disable
+ * various features for performance, and for instanced objects avoid traversing
+ * other parts of the scene.
+ *
+ * BVH_MOTION: motion blur rendering
+ */
+
+#ifndef __KERNEL_GPU__
+ccl_device
+#else
+ccl_device_inline
+#endif
+ bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals kg,
+ ccl_private const Ray *ray,
+ ccl_private LocalIntersection *local_isect,
+ int local_object,
+ ccl_private uint *lcg_state,
+ int max_hits)
+{
+ /* todo:
+ * - test if pushing distance on the stack helps (for non shadow rays)
+ * - separate version for shadow rays
+ * - likely and unlikely for if() statements
+ * - test restrict attribute for pointers
+ */
+
+ /* traversal stack in CUDA thread-local memory */
+ int traversal_stack[BVH_STACK_SIZE];
+ traversal_stack[0] = ENTRYPOINT_SENTINEL;
+
+ /* traversal variables in registers */
+ int stack_ptr = 0;
+ int node_addr = kernel_tex_fetch(__object_node, local_object);
+
+ /* ray parameters in registers */
+ float3 P = ray->P;
+ float3 dir = bvh_clamp_direction(ray->D);
+ float3 idir = bvh_inverse_direction(dir);
+ int object = OBJECT_NONE;
+ float isect_t = ray->t;
+
+ if (local_isect != NULL) {
+ local_isect->num_hits = 0;
+ }
+ kernel_assert((local_isect == NULL) == (max_hits == 0));
+
+ const int object_flag = kernel_tex_fetch(__object_flag, local_object);
+ if (!(object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
+#if BVH_FEATURE(BVH_MOTION)
+ Transform ob_itfm;
+ isect_t *= bvh_instance_motion_push(kg, local_object, ray, &P, &dir, &idir, &ob_itfm);
+#else
+ isect_t *= bvh_instance_push(kg, local_object, ray, &P, &dir, &idir);
+#endif
+ object = local_object;
+ }
+
+ /* traversal loop */
+ do {
+ do {
+ /* traverse internal nodes */
+ while (node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) {
+ int node_addr_child1, traverse_mask;
+ float dist[2];
+ float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr + 0);
+
+ traverse_mask = NODE_INTERSECT(kg,
+ P,
+#if BVH_FEATURE(BVH_HAIR)
+ dir,
+#endif
+ idir,
+ isect_t,
+ node_addr,
+ PATH_RAY_ALL_VISIBILITY,
+ dist);
+
+ node_addr = __float_as_int(cnodes.z);
+ node_addr_child1 = __float_as_int(cnodes.w);
+
+ if (traverse_mask == 3) {
+ /* Both children were intersected, push the farther one. */
+ bool is_closest_child1 = (dist[1] < dist[0]);
+ if (is_closest_child1) {
+ int tmp = node_addr;
+ node_addr = node_addr_child1;
+ node_addr_child1 = tmp;
+ }
+
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_STACK_SIZE);
+ traversal_stack[stack_ptr] = node_addr_child1;
+ }
+ else {
+ /* One child was intersected. */
+ if (traverse_mask == 2) {
+ node_addr = node_addr_child1;
+ }
+ else if (traverse_mask == 0) {
+ /* Neither child was intersected. */
+ node_addr = traversal_stack[stack_ptr];
+ --stack_ptr;
+ }
+ }
+ }
+
+ /* if node is leaf, fetch triangle list */
+ if (node_addr < 0) {
+ float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr - 1));
+ int prim_addr = __float_as_int(leaf.x);
+
+ const int prim_addr2 = __float_as_int(leaf.y);
+ const uint type = __float_as_int(leaf.w);
+
+ /* pop */
+ node_addr = traversal_stack[stack_ptr];
+ --stack_ptr;
+
+ /* primitive intersection */
+ switch (type & PRIMITIVE_ALL) {
+ case PRIMITIVE_TRIANGLE: {
+ /* intersect ray against primitive */
+ for (; prim_addr < prim_addr2; prim_addr++) {
+ kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
+
+ /* 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) {
+ continue;
+ }
+ }
+
+ /* Skip self intersection. */
+ const int prim = kernel_tex_fetch(__prim_index, prim_addr);
+ if (intersection_skip_self_local(ray->self, prim)) {
+ continue;
+ }
+
+ if (triangle_intersect_local(kg,
+ local_isect,
+ P,
+ dir,
+ local_object,
+ prim,
+ prim_addr,
+ isect_t,
+ lcg_state,
+ max_hits)) {
+ return true;
+ }
+ }
+ break;
+ }
+#if BVH_FEATURE(BVH_MOTION)
+ case PRIMITIVE_MOTION_TRIANGLE: {
+ /* intersect ray against primitive */
+ for (; prim_addr < prim_addr2; prim_addr++) {
+ kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
+
+ /* 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) {
+ continue;
+ }
+ }
+
+ /* Skip self intersection. */
+ const int prim = kernel_tex_fetch(__prim_index, prim_addr);
+ if (intersection_skip_self_local(ray->self, prim)) {
+ continue;
+ }
+
+ if (motion_triangle_intersect_local(kg,
+ local_isect,
+ P,
+ dir,
+ ray->time,
+ local_object,
+ prim,
+ prim_addr,
+ isect_t,
+ lcg_state,
+ max_hits)) {
+ return true;
+ }
+ }
+ break;
+ }
+#endif
+ default: {
+ break;
+ }
+ }
+ }
+ } while (node_addr != ENTRYPOINT_SENTINEL);
+ } while (node_addr != ENTRYPOINT_SENTINEL);
+
+ return false;
+}
+
+ccl_device_inline bool BVH_FUNCTION_NAME(KernelGlobals kg,
+ ccl_private const Ray *ray,
+ ccl_private LocalIntersection *local_isect,
+ int local_object,
+ ccl_private uint *lcg_state,
+ int max_hits)
+{
+ return BVH_FUNCTION_FULL_NAME(BVH)(kg, ray, local_isect, local_object, lcg_state, max_hits);
+}
+
+#undef BVH_FUNCTION_NAME
+#undef BVH_FUNCTION_FEATURES
+#undef NODE_INTERSECT
diff --git a/intern/cycles/kernel/bvh/metal.h b/intern/cycles/kernel/bvh/metal.h
new file mode 100644
index 00000000000..5ab413d9314
--- /dev/null
+++ b/intern/cycles/kernel/bvh/metal.h
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+struct MetalRTIntersectionPayload {
+ RaySelfPrimitives self;
+ uint visibility;
+ float u, v;
+ int prim;
+ int type;
+#if defined(__METALRT_MOTION__)
+ float time;
+#endif
+};
+
+struct MetalRTIntersectionLocalPayload {
+ RaySelfPrimitives self;
+ uint local_object;
+ uint lcg_state;
+ short max_hits;
+ bool has_lcg_state;
+ bool result;
+ LocalIntersection local_isect;
+};
+
+struct MetalRTIntersectionShadowPayload {
+ RaySelfPrimitives self;
+ uint visibility;
+#if defined(__METALRT_MOTION__)
+ float time;
+#endif
+ int state;
+ float throughput;
+ short max_hits;
+ short num_hits;
+ short num_recorded_hits;
+ bool result;
+};
diff --git a/intern/cycles/kernel/bvh/nodes.h b/intern/cycles/kernel/bvh/nodes.h
new file mode 100644
index 00000000000..71122085f69
--- /dev/null
+++ b/intern/cycles/kernel/bvh/nodes.h
@@ -0,0 +1,153 @@
+/*
+ * 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.
+ */
+
+// TODO(sergey): Look into avoid use of full Transform and use 3x3 matrix and
+// 3-vector which might be faster.
+ccl_device_forceinline Transform bvh_unaligned_node_fetch_space(KernelGlobals kg,
+ int node_addr,
+ int child)
+{
+ Transform space;
+ const int child_addr = node_addr + child * 3;
+ space.x = kernel_tex_fetch(__bvh_nodes, child_addr + 1);
+ space.y = kernel_tex_fetch(__bvh_nodes, child_addr + 2);
+ space.z = kernel_tex_fetch(__bvh_nodes, child_addr + 3);
+ return space;
+}
+
+ccl_device_forceinline int bvh_aligned_node_intersect(KernelGlobals kg,
+ const float3 P,
+ const float3 idir,
+ const float t,
+ const int node_addr,
+ const uint visibility,
+ float dist[2])
+{
+
+ /* fetch node data */
+#ifdef __VISIBILITY_FLAG__
+ float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr + 0);
+#endif
+ float4 node0 = kernel_tex_fetch(__bvh_nodes, node_addr + 1);
+ float4 node1 = kernel_tex_fetch(__bvh_nodes, node_addr + 2);
+ float4 node2 = kernel_tex_fetch(__bvh_nodes, node_addr + 3);
+
+ /* intersect ray against child nodes */
+ float c0lox = (node0.x - P.x) * idir.x;
+ float c0hix = (node0.z - P.x) * idir.x;
+ float c0loy = (node1.x - P.y) * idir.y;
+ float c0hiy = (node1.z - P.y) * idir.y;
+ float c0loz = (node2.x - P.z) * idir.z;
+ float c0hiz = (node2.z - P.z) * idir.z;
+ float c0min = max4(0.0f, min(c0lox, c0hix), min(c0loy, c0hiy), min(c0loz, c0hiz));
+ float c0max = min4(t, max(c0lox, c0hix), max(c0loy, c0hiy), max(c0loz, c0hiz));
+
+ float c1lox = (node0.y - P.x) * idir.x;
+ float c1hix = (node0.w - P.x) * idir.x;
+ float c1loy = (node1.y - P.y) * idir.y;
+ float c1hiy = (node1.w - P.y) * idir.y;
+ float c1loz = (node2.y - P.z) * idir.z;
+ float c1hiz = (node2.w - P.z) * idir.z;
+ float c1min = max4(0.0f, min(c1lox, c1hix), min(c1loy, c1hiy), min(c1loz, c1hiz));
+ float c1max = min4(t, max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz));
+
+ dist[0] = c0min;
+ dist[1] = c1min;
+
+#ifdef __VISIBILITY_FLAG__
+ /* this visibility test gives a 5% performance hit, how to solve? */
+ return (((c0max >= c0min) && (__float_as_uint(cnodes.x) & visibility)) ? 1 : 0) |
+ (((c1max >= c1min) && (__float_as_uint(cnodes.y) & visibility)) ? 2 : 0);
+#else
+ return ((c0max >= c0min) ? 1 : 0) | ((c1max >= c1min) ? 2 : 0);
+#endif
+}
+
+ccl_device_forceinline bool bvh_unaligned_node_intersect_child(KernelGlobals kg,
+ const float3 P,
+ const float3 dir,
+ const float t,
+ int node_addr,
+ int child,
+ float dist[2])
+{
+ Transform space = bvh_unaligned_node_fetch_space(kg, node_addr, child);
+ float3 aligned_dir = transform_direction(&space, dir);
+ float3 aligned_P = transform_point(&space, P);
+ float3 nrdir = -bvh_inverse_direction(aligned_dir);
+ float3 lower_xyz = aligned_P * nrdir;
+ float3 upper_xyz = lower_xyz - nrdir;
+ const float near_x = min(lower_xyz.x, upper_xyz.x);
+ const float near_y = min(lower_xyz.y, upper_xyz.y);
+ const float near_z = min(lower_xyz.z, upper_xyz.z);
+ const float far_x = max(lower_xyz.x, upper_xyz.x);
+ const float far_y = max(lower_xyz.y, upper_xyz.y);
+ const float far_z = max(lower_xyz.z, upper_xyz.z);
+ const float tnear = max4(0.0f, near_x, near_y, near_z);
+ const float tfar = min4(t, far_x, far_y, far_z);
+ *dist = tnear;
+ return tnear <= tfar;
+}
+
+ccl_device_forceinline int bvh_unaligned_node_intersect(KernelGlobals kg,
+ const float3 P,
+ const float3 dir,
+ const float3 idir,
+ const float t,
+ const int node_addr,
+ const uint visibility,
+ float dist[2])
+{
+ int mask = 0;
+#ifdef __VISIBILITY_FLAG__
+ float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr + 0);
+#endif
+ if (bvh_unaligned_node_intersect_child(kg, P, dir, t, node_addr, 0, &dist[0])) {
+#ifdef __VISIBILITY_FLAG__
+ if ((__float_as_uint(cnodes.x) & visibility))
+#endif
+ {
+ mask |= 1;
+ }
+ }
+ if (bvh_unaligned_node_intersect_child(kg, P, dir, t, node_addr, 1, &dist[1])) {
+#ifdef __VISIBILITY_FLAG__
+ if ((__float_as_uint(cnodes.y) & visibility))
+#endif
+ {
+ mask |= 2;
+ }
+ }
+ return mask;
+}
+
+ccl_device_forceinline int bvh_node_intersect(KernelGlobals kg,
+ const float3 P,
+ const float3 dir,
+ const float3 idir,
+ const float t,
+ const int node_addr,
+ const uint visibility,
+ float dist[2])
+{
+ float4 node = kernel_tex_fetch(__bvh_nodes, node_addr);
+ if (__float_as_uint(node.x) & PATH_RAY_NODE_UNALIGNED) {
+ return bvh_unaligned_node_intersect(kg, P, dir, idir, t, node_addr, visibility, dist);
+ }
+ else {
+ return bvh_aligned_node_intersect(kg, P, idir, t, node_addr, visibility, dist);
+ }
+}
diff --git a/intern/cycles/kernel/bvh/shadow_all.h b/intern/cycles/kernel/bvh/shadow_all.h
new file mode 100644
index 00000000000..59a7ba63045
--- /dev/null
+++ b/intern/cycles/kernel/bvh/shadow_all.h
@@ -0,0 +1,360 @@
+/*
+ * Adapted from code Copyright 2009-2010 NVIDIA Corporation,
+ * and code copyright 2009-2012 Intel Corporation
+ *
+ * Modifications Copyright 2011-2013, Blender Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 BVH_FEATURE(BVH_HAIR)
+# define NODE_INTERSECT bvh_node_intersect
+#else
+# define NODE_INTERSECT bvh_aligned_node_intersect
+#endif
+
+/* This is a template BVH traversal function, where various features can be
+ * enabled/disabled. This way we can compile optimized versions for each case
+ * without new features slowing things down.
+ *
+ * BVH_HAIR: hair curve rendering
+ * BVH_POINTCLOUD: point cloud rendering
+ * BVH_MOTION: motion blur rendering
+ */
+
+#ifndef __KERNEL_GPU__
+ccl_device
+#else
+ccl_device_inline
+#endif
+ bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals kg,
+ ccl_private const Ray *ray,
+ IntegratorShadowState state,
+ const uint visibility,
+ const uint max_hits,
+ ccl_private uint *num_recorded_hits,
+ ccl_private float *throughput)
+{
+ /* todo:
+ * - likely and unlikely for if() statements
+ * - test restrict attribute for pointers
+ */
+
+ /* traversal stack in CUDA thread-local memory */
+ int traversal_stack[BVH_STACK_SIZE];
+ traversal_stack[0] = ENTRYPOINT_SENTINEL;
+
+ /* traversal variables in registers */
+ int stack_ptr = 0;
+ int node_addr = kernel_data.bvh.root;
+
+ /* ray parameters in registers */
+ float3 P = ray->P;
+ float3 dir = bvh_clamp_direction(ray->D);
+ float3 idir = bvh_inverse_direction(dir);
+ int object = OBJECT_NONE;
+ uint num_hits = 0;
+
+#if BVH_FEATURE(BVH_MOTION)
+ Transform ob_itfm;
+#endif
+
+ /* Max distance in world space. May be dynamically reduced when max number of
+ * recorded hits is exceeded and we no longer need to find hits beyond the max
+ * distance found. */
+ float t_max_world = ray->t;
+ /* Equal to t_max_world when traversing top level BVH, transformed into local
+ * space when entering instances. */
+ float t_max_current = t_max_world;
+ /* Conversion from world to local space for the current instance if any, 1.0
+ * otherwise. */
+ float t_world_to_instance = 1.0f;
+
+ *num_recorded_hits = 0;
+ *throughput = 1.0f;
+
+ /* traversal loop */
+ do {
+ do {
+ /* traverse internal nodes */
+ while (node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) {
+ int node_addr_child1, traverse_mask;
+ float dist[2];
+ float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr + 0);
+
+ traverse_mask = NODE_INTERSECT(kg,
+ P,
+#if BVH_FEATURE(BVH_HAIR)
+ dir,
+#endif
+ idir,
+ t_max_current,
+ node_addr,
+ visibility,
+ dist);
+
+ node_addr = __float_as_int(cnodes.z);
+ node_addr_child1 = __float_as_int(cnodes.w);
+
+ if (traverse_mask == 3) {
+ /* Both children were intersected, push the farther one. */
+ bool is_closest_child1 = (dist[1] < dist[0]);
+ if (is_closest_child1) {
+ int tmp = node_addr;
+ node_addr = node_addr_child1;
+ node_addr_child1 = tmp;
+ }
+
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_STACK_SIZE);
+ traversal_stack[stack_ptr] = node_addr_child1;
+ }
+ else {
+ /* One child was intersected. */
+ if (traverse_mask == 2) {
+ node_addr = node_addr_child1;
+ }
+ else if (traverse_mask == 0) {
+ /* Neither child was intersected. */
+ node_addr = traversal_stack[stack_ptr];
+ --stack_ptr;
+ }
+ }
+ }
+
+ /* if node is leaf, fetch triangle list */
+ if (node_addr < 0) {
+ float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr - 1));
+ int prim_addr = __float_as_int(leaf.x);
+
+ if (prim_addr >= 0) {
+ const int prim_addr2 = __float_as_int(leaf.y);
+ const uint type = __float_as_int(leaf.w);
+
+ /* pop */
+ node_addr = traversal_stack[stack_ptr];
+ --stack_ptr;
+
+ /* primitive intersection */
+ for (; prim_addr < prim_addr2; prim_addr++) {
+ kernel_assert((kernel_tex_fetch(__prim_type, prim_addr) & PRIMITIVE_ALL) ==
+ (type & PRIMITIVE_ALL));
+ bool hit;
+
+ /* todo: specialized intersect functions which don't fill in
+ * isect unless needed and check SD_HAS_TRANSPARENT_SHADOW?
+ * might give a few % performance improvement */
+ Intersection isect ccl_optional_struct_init;
+
+ const int prim_object = (object == OBJECT_NONE) ?
+ kernel_tex_fetch(__prim_object, prim_addr) :
+ object;
+ const int prim = kernel_tex_fetch(__prim_index, prim_addr);
+ if (intersection_skip_self_shadow(ray->self, prim_object, prim)) {
+ continue;
+ }
+
+ switch (type & PRIMITIVE_ALL) {
+ case PRIMITIVE_TRIANGLE: {
+ hit = triangle_intersect(
+ kg, &isect, P, dir, t_max_current, visibility, prim_object, prim, prim_addr);
+ break;
+ }
+#if BVH_FEATURE(BVH_MOTION)
+ case PRIMITIVE_MOTION_TRIANGLE: {
+ hit = motion_triangle_intersect(kg,
+ &isect,
+ P,
+ dir,
+ t_max_current,
+ ray->time,
+ visibility,
+ prim_object,
+ prim,
+ prim_addr);
+ break;
+ }
+#endif
+#if BVH_FEATURE(BVH_HAIR)
+ case PRIMITIVE_CURVE_THICK:
+ case PRIMITIVE_MOTION_CURVE_THICK:
+ case PRIMITIVE_CURVE_RIBBON:
+ case PRIMITIVE_MOTION_CURVE_RIBBON: {
+ if ((type & PRIMITIVE_MOTION) && kernel_data.bvh.use_bvh_steps) {
+ const float2 prim_time = kernel_tex_fetch(__prim_time, prim_addr);
+ if (ray->time < prim_time.x || ray->time > prim_time.y) {
+ hit = false;
+ break;
+ }
+ }
+
+ const int curve_type = kernel_tex_fetch(__prim_type, prim_addr);
+ hit = curve_intersect(
+ kg, &isect, P, dir, t_max_current, prim_object, prim, ray->time, curve_type);
+
+ break;
+ }
+#endif
+#if BVH_FEATURE(BVH_POINTCLOUD)
+ case PRIMITIVE_POINT:
+ case PRIMITIVE_MOTION_POINT: {
+ if ((type & PRIMITIVE_MOTION) && kernel_data.bvh.use_bvh_steps) {
+ const float2 prim_time = kernel_tex_fetch(__prim_time, prim_addr);
+ if (ray->time < prim_time.x || ray->time > prim_time.y) {
+ hit = false;
+ break;
+ }
+ }
+
+ const int point_type = kernel_tex_fetch(__prim_type, prim_addr);
+ hit = point_intersect(
+ kg, &isect, P, dir, t_max_current, prim_object, prim, ray->time, point_type);
+ break;
+ }
+#endif /* BVH_FEATURE(BVH_POINTCLOUD) */
+ default: {
+ hit = false;
+ break;
+ }
+ }
+
+ /* shadow ray early termination */
+ if (hit) {
+ /* Convert intersection distance to world space. */
+ isect.t /= t_world_to_instance;
+
+ /* detect if this surface has a shader with transparent shadows */
+ /* todo: optimize so primitive visibility flag indicates if
+ * the primitive has a transparent shadow shader? */
+ const int flags = intersection_get_shader_flags(kg, isect.prim, isect.type);
+
+ if (!(flags & SD_HAS_TRANSPARENT_SHADOW) || num_hits >= max_hits) {
+ /* If no transparent shadows, all light is blocked and we can
+ * stop immediately. */
+ return true;
+ }
+
+ num_hits++;
+
+ bool record_intersection = true;
+
+ /* Always use baked shadow transparency for curves. */
+ if (isect.type & PRIMITIVE_CURVE) {
+ *throughput *= intersection_curve_shadow_transparency(
+ kg, isect.object, isect.prim, isect.u);
+
+ if (*throughput < CURVE_SHADOW_TRANSPARENCY_CUTOFF) {
+ return true;
+ }
+ else {
+ record_intersection = false;
+ }
+ }
+
+ if (record_intersection) {
+ /* Increase the number of hits, possibly beyond max_hits, we will
+ * simply not record those and only keep the max_hits closest. */
+ uint record_index = (*num_recorded_hits)++;
+
+ const uint max_record_hits = min(max_hits, INTEGRATOR_SHADOW_ISECT_SIZE);
+ if (record_index >= max_record_hits - 1) {
+ /* If maximum number of hits reached, find the intersection with
+ * the largest distance to potentially replace when another hit
+ * is found. */
+ const int num_recorded_hits = min(max_record_hits, record_index);
+ float max_recorded_t = INTEGRATOR_STATE_ARRAY(state, shadow_isect, 0, t);
+ int max_recorded_hit = 0;
+
+ for (int i = 1; i < num_recorded_hits; i++) {
+ const float isect_t = INTEGRATOR_STATE_ARRAY(state, shadow_isect, i, t);
+ if (isect_t > max_recorded_t) {
+ max_recorded_t = isect_t;
+ max_recorded_hit = i;
+ }
+ }
+
+ if (record_index >= max_record_hits) {
+ record_index = max_recorded_hit;
+ }
+
+ /* Limit the ray distance and stop counting hits beyond this. */
+ t_max_world = max(max_recorded_t, isect.t);
+ t_max_current = t_max_world * t_world_to_instance;
+ }
+
+ integrator_state_write_shadow_isect(state, &isect, record_index);
+ }
+ }
+ }
+ }
+ else {
+ /* instance push */
+ object = kernel_tex_fetch(__prim_object, -prim_addr - 1);
+
+#if BVH_FEATURE(BVH_MOTION)
+ t_world_to_instance = bvh_instance_motion_push(
+ kg, object, ray, &P, &dir, &idir, &ob_itfm);
+#else
+ t_world_to_instance = bvh_instance_push(kg, object, ray, &P, &dir, &idir);
+#endif
+
+ /* Convert intersection to object space. */
+ t_max_current *= t_world_to_instance;
+
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_STACK_SIZE);
+ traversal_stack[stack_ptr] = ENTRYPOINT_SENTINEL;
+
+ node_addr = kernel_tex_fetch(__object_node, object);
+ }
+ }
+ } while (node_addr != ENTRYPOINT_SENTINEL);
+
+ if (stack_ptr >= 0) {
+ kernel_assert(object != OBJECT_NONE);
+
+ /* Instance pop. */
+#if BVH_FEATURE(BVH_MOTION)
+ bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir, FLT_MAX, &ob_itfm);
+#else
+ bvh_instance_pop(kg, object, ray, &P, &dir, &idir, FLT_MAX);
+#endif
+
+ /* Restore world space ray length. */
+ t_max_current = t_max_world;
+
+ object = OBJECT_NONE;
+ t_world_to_instance = 1.0f;
+ node_addr = traversal_stack[stack_ptr];
+ --stack_ptr;
+ }
+ } while (node_addr != ENTRYPOINT_SENTINEL);
+
+ return false;
+}
+
+ccl_device_inline bool BVH_FUNCTION_NAME(KernelGlobals kg,
+ ccl_private const Ray *ray,
+ IntegratorShadowState state,
+ const uint visibility,
+ const uint max_hits,
+ ccl_private uint *num_recorded_hits,
+ ccl_private float *throughput)
+{
+ return BVH_FUNCTION_FULL_NAME(BVH)(
+ kg, ray, state, visibility, max_hits, num_recorded_hits, throughput);
+}
+
+#undef BVH_FUNCTION_NAME
+#undef BVH_FUNCTION_FEATURES
+#undef NODE_INTERSECT
diff --git a/intern/cycles/kernel/bvh/traversal.h b/intern/cycles/kernel/bvh/traversal.h
new file mode 100644
index 00000000000..17cd357a069
--- /dev/null
+++ b/intern/cycles/kernel/bvh/traversal.h
@@ -0,0 +1,271 @@
+/*
+ * Adapted from code Copyright 2009-2010 NVIDIA Corporation,
+ * and code copyright 2009-2012 Intel Corporation
+ *
+ * Modifications Copyright 2011-2013, Blender Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 BVH_FEATURE(BVH_HAIR)
+# define NODE_INTERSECT bvh_node_intersect
+#else
+# define NODE_INTERSECT bvh_aligned_node_intersect
+#endif
+
+/* This is a template BVH traversal function, where various features can be
+ * enabled/disabled. This way we can compile optimized versions for each case
+ * without new features slowing things down.
+ *
+ * BVH_HAIR: hair curve rendering
+ * BVH_POINTCLOUD: point cloud rendering
+ * BVH_MOTION: motion blur rendering
+ */
+
+ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals kg,
+ ccl_private const Ray *ray,
+ ccl_private Intersection *isect,
+ const uint visibility)
+{
+ /* todo:
+ * - test if pushing distance on the stack helps (for non shadow rays)
+ * - separate version for shadow rays
+ * - likely and unlikely for if() statements
+ * - test restrict attribute for pointers
+ */
+
+ /* traversal stack in CUDA thread-local memory */
+ int traversal_stack[BVH_STACK_SIZE];
+ traversal_stack[0] = ENTRYPOINT_SENTINEL;
+
+ /* traversal variables in registers */
+ int stack_ptr = 0;
+ int node_addr = kernel_data.bvh.root;
+
+ /* ray parameters in registers */
+ float3 P = ray->P;
+ float3 dir = bvh_clamp_direction(ray->D);
+ float3 idir = bvh_inverse_direction(dir);
+ int object = OBJECT_NONE;
+
+#if BVH_FEATURE(BVH_MOTION)
+ Transform ob_itfm;
+#endif
+
+ isect->t = ray->t;
+ isect->u = 0.0f;
+ isect->v = 0.0f;
+ isect->prim = PRIM_NONE;
+ isect->object = OBJECT_NONE;
+
+ /* traversal loop */
+ do {
+ do {
+ /* traverse internal nodes */
+ while (node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) {
+ int node_addr_child1, traverse_mask;
+ float dist[2];
+ float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr + 0);
+
+ {
+ traverse_mask = NODE_INTERSECT(kg,
+ P,
+#if BVH_FEATURE(BVH_HAIR)
+ dir,
+#endif
+ idir,
+ isect->t,
+ node_addr,
+ visibility,
+ dist);
+ }
+
+ node_addr = __float_as_int(cnodes.z);
+ node_addr_child1 = __float_as_int(cnodes.w);
+
+ if (traverse_mask == 3) {
+ /* Both children were intersected, push the farther one. */
+ bool is_closest_child1 = (dist[1] < dist[0]);
+ if (is_closest_child1) {
+ int tmp = node_addr;
+ node_addr = node_addr_child1;
+ node_addr_child1 = tmp;
+ }
+
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_STACK_SIZE);
+ traversal_stack[stack_ptr] = node_addr_child1;
+ }
+ else {
+ /* One child was intersected. */
+ if (traverse_mask == 2) {
+ node_addr = node_addr_child1;
+ }
+ else if (traverse_mask == 0) {
+ /* Neither child was intersected. */
+ node_addr = traversal_stack[stack_ptr];
+ --stack_ptr;
+ }
+ }
+ }
+
+ /* if node is leaf, fetch triangle list */
+ if (node_addr < 0) {
+ float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr - 1));
+ int prim_addr = __float_as_int(leaf.x);
+
+ if (prim_addr >= 0) {
+ const int prim_addr2 = __float_as_int(leaf.y);
+ const uint type = __float_as_int(leaf.w);
+
+ /* pop */
+ node_addr = traversal_stack[stack_ptr];
+ --stack_ptr;
+
+ /* primitive intersection */
+ for (; prim_addr < prim_addr2; prim_addr++) {
+ kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
+
+ const int prim_object = (object == OBJECT_NONE) ?
+ kernel_tex_fetch(__prim_object, prim_addr) :
+ object;
+ const int prim = kernel_tex_fetch(__prim_index, prim_addr);
+ if (intersection_skip_self_shadow(ray->self, prim_object, prim)) {
+ continue;
+ }
+
+ switch (type & PRIMITIVE_ALL) {
+ case PRIMITIVE_TRIANGLE: {
+ if (triangle_intersect(
+ kg, isect, P, dir, isect->t, visibility, prim_object, prim, prim_addr)) {
+ /* shadow ray early termination */
+ if (visibility & PATH_RAY_SHADOW_OPAQUE)
+ return true;
+ }
+ break;
+ }
+#if BVH_FEATURE(BVH_MOTION)
+ case PRIMITIVE_MOTION_TRIANGLE: {
+ if (motion_triangle_intersect(kg,
+ isect,
+ P,
+ dir,
+ isect->t,
+ ray->time,
+ visibility,
+ prim_object,
+ prim,
+ prim_addr)) {
+ /* shadow ray early termination */
+ if (visibility & PATH_RAY_SHADOW_OPAQUE)
+ return true;
+ }
+ break;
+ }
+#endif /* BVH_FEATURE(BVH_MOTION) */
+#if BVH_FEATURE(BVH_HAIR)
+ case PRIMITIVE_CURVE_THICK:
+ case PRIMITIVE_MOTION_CURVE_THICK:
+ case PRIMITIVE_CURVE_RIBBON:
+ case PRIMITIVE_MOTION_CURVE_RIBBON: {
+ if ((type & PRIMITIVE_MOTION) && kernel_data.bvh.use_bvh_steps) {
+ const float2 prim_time = kernel_tex_fetch(__prim_time, prim_addr);
+ if (ray->time < prim_time.x || ray->time > prim_time.y) {
+ break;
+ }
+ }
+
+ const int curve_type = kernel_tex_fetch(__prim_type, prim_addr);
+ const bool hit = curve_intersect(
+ kg, isect, P, dir, isect->t, prim_object, prim, ray->time, curve_type);
+ if (hit) {
+ /* shadow ray early termination */
+ if (visibility & PATH_RAY_SHADOW_OPAQUE)
+ return true;
+ }
+ break;
+ }
+#endif /* BVH_FEATURE(BVH_HAIR) */
+#if BVH_FEATURE(BVH_POINTCLOUD)
+ case PRIMITIVE_POINT:
+ case PRIMITIVE_MOTION_POINT: {
+ if ((type & PRIMITIVE_MOTION) && kernel_data.bvh.use_bvh_steps) {
+ const float2 prim_time = kernel_tex_fetch(__prim_time, prim_addr);
+ if (ray->time < prim_time.x || ray->time > prim_time.y) {
+ break;
+ }
+ }
+
+ const int point_type = kernel_tex_fetch(__prim_type, prim_addr);
+ const bool hit = point_intersect(
+ kg, isect, P, dir, isect->t, prim_object, prim, ray->time, point_type);
+ if (hit) {
+ /* shadow ray early termination */
+ if (visibility & PATH_RAY_SHADOW_OPAQUE)
+ return true;
+ }
+ break;
+ }
+#endif /* BVH_FEATURE(BVH_POINTCLOUD) */
+ }
+ }
+ }
+ else {
+ /* instance push */
+ object = kernel_tex_fetch(__prim_object, -prim_addr - 1);
+
+#if BVH_FEATURE(BVH_MOTION)
+ isect->t *= bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &ob_itfm);
+#else
+ isect->t *= bvh_instance_push(kg, object, ray, &P, &dir, &idir);
+#endif
+
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_STACK_SIZE);
+ traversal_stack[stack_ptr] = ENTRYPOINT_SENTINEL;
+
+ node_addr = kernel_tex_fetch(__object_node, object);
+ }
+ }
+ } while (node_addr != ENTRYPOINT_SENTINEL);
+
+ if (stack_ptr >= 0) {
+ kernel_assert(object != OBJECT_NONE);
+
+ /* instance pop */
+#if BVH_FEATURE(BVH_MOTION)
+ isect->t = bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir, isect->t, &ob_itfm);
+#else
+ isect->t = bvh_instance_pop(kg, object, ray, &P, &dir, &idir, isect->t);
+#endif
+
+ object = OBJECT_NONE;
+ node_addr = traversal_stack[stack_ptr];
+ --stack_ptr;
+ }
+ } while (node_addr != ENTRYPOINT_SENTINEL);
+
+ return (isect->prim != PRIM_NONE);
+}
+
+ccl_device_inline bool BVH_FUNCTION_NAME(KernelGlobals kg,
+ ccl_private const Ray *ray,
+ ccl_private Intersection *isect,
+ const uint visibility)
+{
+ return BVH_FUNCTION_FULL_NAME(BVH)(kg, ray, isect, visibility);
+}
+
+#undef BVH_FUNCTION_NAME
+#undef BVH_FUNCTION_FEATURES
+#undef NODE_INTERSECT
diff --git a/intern/cycles/kernel/bvh/types.h b/intern/cycles/kernel/bvh/types.h
new file mode 100644
index 00000000000..f16f43333f8
--- /dev/null
+++ b/intern/cycles/kernel/bvh/types.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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
+
+/* Don't inline intersect functions on GPU, this is faster */
+#ifdef __KERNEL_GPU__
+# define ccl_device_intersect ccl_device_forceinline
+#else
+# define ccl_device_intersect ccl_device_inline
+#endif
+
+/* bottom-most stack entry, indicating the end of traversal */
+#define ENTRYPOINT_SENTINEL 0x76543210
+
+/* 64 object BVH + 64 mesh BVH + 64 object node splitting */
+#define BVH_STACK_SIZE 192
+/* BVH intersection function variations */
+
+#define BVH_MOTION 1
+#define BVH_HAIR 2
+#define BVH_POINTCLOUD 4
+
+#define BVH_NAME_JOIN(x, y) x##_##y
+#define BVH_NAME_EVAL(x, y) BVH_NAME_JOIN(x, y)
+#define BVH_FUNCTION_FULL_NAME(prefix) BVH_NAME_EVAL(prefix, BVH_FUNCTION_NAME)
+
+#define BVH_FEATURE(f) (((BVH_FUNCTION_FEATURES) & (f)) != 0)
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/bvh/util.h b/intern/cycles/kernel/bvh/util.h
new file mode 100644
index 00000000000..39c3ecd78c0
--- /dev/null
+++ b/intern/cycles/kernel/bvh/util.h
@@ -0,0 +1,219 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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
+
+/* Ray offset to avoid self intersection.
+ *
+ * This function should be used to compute a modified ray start position for
+ * rays leaving from a surface. This is from "A Fast and Robust Method for Avoiding
+ * Self-Intersection" see https://research.nvidia.com/publication/2019-03_A-Fast-and
+ */
+ccl_device_inline float3 ray_offset(float3 P, float3 Ng)
+{
+ const float int_scale = 256.0f;
+ int3 of_i = make_int3((int)(int_scale * Ng.x), (int)(int_scale * Ng.y), (int)(int_scale * Ng.z));
+
+ float3 p_i = make_float3(__int_as_float(__float_as_int(P.x) + ((P.x < 0) ? -of_i.x : of_i.x)),
+ __int_as_float(__float_as_int(P.y) + ((P.y < 0) ? -of_i.y : of_i.y)),
+ __int_as_float(__float_as_int(P.z) + ((P.z < 0) ? -of_i.z : of_i.z)));
+ const float origin = 1.0f / 32.0f;
+ const float float_scale = 1.0f / 65536.0f;
+ return make_float3(fabsf(P.x) < origin ? P.x + float_scale * Ng.x : p_i.x,
+ fabsf(P.y) < origin ? P.y + float_scale * Ng.y : p_i.y,
+ fabsf(P.z) < origin ? P.z + float_scale * Ng.z : p_i.z);
+}
+
+#if defined(__KERNEL_CPU__)
+ccl_device int intersections_compare(const void *a, const void *b)
+{
+ const Intersection *isect_a = (const Intersection *)a;
+ const Intersection *isect_b = (const Intersection *)b;
+
+ if (isect_a->t < isect_b->t)
+ return -1;
+ else if (isect_a->t > isect_b->t)
+ return 1;
+ else
+ return 0;
+}
+#endif
+
+/* For subsurface scattering, only sorting a small amount of intersections
+ * so bubble sort is fine for CPU and GPU. */
+ccl_device_inline void sort_intersections_and_normals(ccl_private Intersection *hits,
+ ccl_private float3 *Ng,
+ uint num_hits)
+{
+ bool swapped;
+ do {
+ swapped = false;
+ for (int j = 0; j < num_hits - 1; ++j) {
+ if (hits[j].t > hits[j + 1].t) {
+ Intersection tmp_hit = hits[j];
+ float3 tmp_Ng = Ng[j];
+ hits[j] = hits[j + 1];
+ Ng[j] = Ng[j + 1];
+ hits[j + 1] = tmp_hit;
+ Ng[j + 1] = tmp_Ng;
+ swapped = true;
+ }
+ }
+ --num_hits;
+ } while (swapped);
+}
+
+/* Utility to quickly get flags from an intersection. */
+
+ccl_device_forceinline int intersection_get_shader_flags(KernelGlobals kg,
+ const int prim,
+ const int type)
+{
+ int shader = 0;
+
+ if (type & PRIMITIVE_TRIANGLE) {
+ shader = kernel_tex_fetch(__tri_shader, prim);
+ }
+#ifdef __POINTCLOUD__
+ else if (type & PRIMITIVE_POINT) {
+ shader = kernel_tex_fetch(__points_shader, prim);
+ }
+#endif
+#ifdef __HAIR__
+ else if (type & PRIMITIVE_CURVE) {
+ shader = kernel_tex_fetch(__curves, prim).shader_id;
+ }
+#endif
+
+ return kernel_tex_fetch(__shaders, (shader & SHADER_MASK)).flags;
+}
+
+ccl_device_forceinline int intersection_get_shader_from_isect_prim(KernelGlobals kg,
+ const int prim,
+ const int isect_type)
+{
+ int shader = 0;
+
+ if (isect_type & PRIMITIVE_TRIANGLE) {
+ shader = kernel_tex_fetch(__tri_shader, prim);
+ }
+#ifdef __POINTCLOUD__
+ else if (isect_type & PRIMITIVE_POINT) {
+ shader = kernel_tex_fetch(__points_shader, prim);
+ }
+#endif
+#ifdef __HAIR__
+ else if (isect_type & PRIMITIVE_CURVE) {
+ shader = kernel_tex_fetch(__curves, prim).shader_id;
+ }
+#endif
+
+ return shader & SHADER_MASK;
+}
+
+ccl_device_forceinline int intersection_get_shader(
+ KernelGlobals kg, ccl_private const Intersection *ccl_restrict isect)
+{
+ return intersection_get_shader_from_isect_prim(kg, isect->prim, isect->type);
+}
+
+ccl_device_forceinline int intersection_get_object_flags(
+ KernelGlobals kg, ccl_private const Intersection *ccl_restrict isect)
+{
+ return kernel_tex_fetch(__object_flag, isect->object);
+}
+
+/* TODO: find a better (faster) solution for this. Maybe store offset per object for
+ * attributes needed in intersection? */
+ccl_device_inline int intersection_find_attribute(KernelGlobals kg,
+ const int object,
+ const uint id)
+{
+ uint attr_offset = kernel_tex_fetch(__objects, object).attribute_map_offset;
+ uint4 attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
+
+ while (attr_map.x != id) {
+ if (UNLIKELY(attr_map.x == ATTR_STD_NONE)) {
+ if (UNLIKELY(attr_map.y == 0)) {
+ return (int)ATTR_STD_NOT_FOUND;
+ }
+ else {
+ /* Chain jump to a different part of the table. */
+ attr_offset = attr_map.z;
+ }
+ }
+ else {
+ attr_offset += ATTR_PRIM_TYPES;
+ }
+ attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
+ }
+
+ /* return result */
+ return (attr_map.y == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : (int)attr_map.z;
+}
+
+/* Transparent Shadows */
+
+/* Cut-off value to stop transparent shadow tracing when practically opaque. */
+#define CURVE_SHADOW_TRANSPARENCY_CUTOFF 0.001f
+
+ccl_device_inline float intersection_curve_shadow_transparency(KernelGlobals kg,
+ const int object,
+ const int prim,
+ const float u)
+{
+ /* Find attribute. */
+ const int offset = intersection_find_attribute(kg, object, ATTR_STD_SHADOW_TRANSPARENCY);
+ if (offset == ATTR_STD_NOT_FOUND) {
+ /* If no shadow transparency attribute, assume opaque. */
+ return 0.0f;
+ }
+
+ /* Interpolate transparency between curve keys. */
+ const KernelCurve kcurve = kernel_tex_fetch(__curves, prim);
+ const int k0 = kcurve.first_key + PRIMITIVE_UNPACK_SEGMENT(kcurve.type);
+ const int k1 = k0 + 1;
+
+ const float f0 = kernel_tex_fetch(__attributes_float, offset + k0);
+ const float f1 = kernel_tex_fetch(__attributes_float, offset + k1);
+
+ return (1.0f - u) * f0 + u * f1;
+}
+
+ccl_device_inline bool intersection_skip_self(ccl_private const RaySelfPrimitives &self,
+ const int object,
+ const int prim)
+{
+ return (self.prim == prim) && (self.object == object);
+}
+
+ccl_device_inline bool intersection_skip_self_shadow(ccl_private const RaySelfPrimitives &self,
+ const int object,
+ const int prim)
+{
+ return ((self.prim == prim) && (self.object == object)) ||
+ ((self.light_prim == prim) && (self.light_object == object));
+}
+
+ccl_device_inline bool intersection_skip_self_local(ccl_private const RaySelfPrimitives &self,
+ const int prim)
+{
+ return (self.prim == prim);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/bvh/volume.h b/intern/cycles/kernel/bvh/volume.h
new file mode 100644
index 00000000000..95bba4f071d
--- /dev/null
+++ b/intern/cycles/kernel/bvh/volume.h
@@ -0,0 +1,252 @@
+/*
+ * Adapted from code Copyright 2009-2010 NVIDIA Corporation,
+ * and code copyright 2009-2012 Intel Corporation
+ *
+ * Modifications 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.
+ */
+
+#if BVH_FEATURE(BVH_HAIR)
+# define NODE_INTERSECT bvh_node_intersect
+#else
+# define NODE_INTERSECT bvh_aligned_node_intersect
+#endif
+
+/* This is a template BVH traversal function for volumes, where
+ * various features can be enabled/disabled. This way we can compile optimized
+ * versions for each case without new features slowing things down.
+ *
+ * BVH_MOTION: motion blur rendering
+ */
+
+#ifndef __KERNEL_GPU__
+ccl_device
+#else
+ccl_device_inline
+#endif
+ bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals kg,
+ ccl_private const Ray *ray,
+ ccl_private Intersection *isect,
+ const uint visibility)
+{
+ /* todo:
+ * - test if pushing distance on the stack helps (for non shadow rays)
+ * - separate version for shadow rays
+ * - likely and unlikely for if() statements
+ * - test restrict attribute for pointers
+ */
+
+ /* traversal stack in CUDA thread-local memory */
+ int traversal_stack[BVH_STACK_SIZE];
+ traversal_stack[0] = ENTRYPOINT_SENTINEL;
+
+ /* traversal variables in registers */
+ int stack_ptr = 0;
+ int node_addr = kernel_data.bvh.root;
+
+ /* ray parameters in registers */
+ float3 P = ray->P;
+ float3 dir = bvh_clamp_direction(ray->D);
+ float3 idir = bvh_inverse_direction(dir);
+ int object = OBJECT_NONE;
+
+#if BVH_FEATURE(BVH_MOTION)
+ Transform ob_itfm;
+#endif
+
+ isect->t = ray->t;
+ isect->u = 0.0f;
+ isect->v = 0.0f;
+ isect->prim = PRIM_NONE;
+ isect->object = OBJECT_NONE;
+
+ /* traversal loop */
+ do {
+ do {
+ /* traverse internal nodes */
+ while (node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) {
+ int node_addr_child1, traverse_mask;
+ float dist[2];
+ float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr + 0);
+
+ traverse_mask = NODE_INTERSECT(kg,
+ P,
+#if BVH_FEATURE(BVH_HAIR)
+ dir,
+#endif
+ idir,
+ isect->t,
+ node_addr,
+ visibility,
+ dist);
+
+ node_addr = __float_as_int(cnodes.z);
+ node_addr_child1 = __float_as_int(cnodes.w);
+
+ if (traverse_mask == 3) {
+ /* Both children were intersected, push the farther one. */
+ bool is_closest_child1 = (dist[1] < dist[0]);
+ if (is_closest_child1) {
+ int tmp = node_addr;
+ node_addr = node_addr_child1;
+ node_addr_child1 = tmp;
+ }
+
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_STACK_SIZE);
+ traversal_stack[stack_ptr] = node_addr_child1;
+ }
+ else {
+ /* One child was intersected. */
+ if (traverse_mask == 2) {
+ node_addr = node_addr_child1;
+ }
+ else if (traverse_mask == 0) {
+ /* Neither child was intersected. */
+ node_addr = traversal_stack[stack_ptr];
+ --stack_ptr;
+ }
+ }
+ }
+
+ /* if node is leaf, fetch triangle list */
+ if (node_addr < 0) {
+ float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr - 1));
+ int prim_addr = __float_as_int(leaf.x);
+
+ if (prim_addr >= 0) {
+ const int prim_addr2 = __float_as_int(leaf.y);
+ const uint type = __float_as_int(leaf.w);
+
+ /* pop */
+ node_addr = traversal_stack[stack_ptr];
+ --stack_ptr;
+
+ /* primitive intersection */
+ switch (type & PRIMITIVE_ALL) {
+ case PRIMITIVE_TRIANGLE: {
+ /* intersect ray against primitive */
+ for (; prim_addr < prim_addr2; prim_addr++) {
+ kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
+ /* only primitives from volume object */
+ const int prim_object = (object == OBJECT_NONE) ?
+ kernel_tex_fetch(__prim_object, prim_addr) :
+ object;
+ const int prim = kernel_tex_fetch(__prim_index, prim_addr);
+ if (intersection_skip_self(ray->self, prim_object, prim)) {
+ continue;
+ }
+
+ int object_flag = kernel_tex_fetch(__object_flag, prim_object);
+ if ((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
+ continue;
+ }
+ triangle_intersect(
+ kg, isect, P, dir, isect->t, visibility, prim_object, prim, prim_addr);
+ }
+ break;
+ }
+#if BVH_FEATURE(BVH_MOTION)
+ case PRIMITIVE_MOTION_TRIANGLE: {
+ /* intersect ray against primitive */
+ for (; prim_addr < prim_addr2; prim_addr++) {
+ kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
+ /* only primitives from volume object */
+ const int prim_object = (object == OBJECT_NONE) ?
+ kernel_tex_fetch(__prim_object, prim_addr) :
+ object;
+ const int prim = kernel_tex_fetch(__prim_index, prim_addr);
+ if (intersection_skip_self(ray->self, prim_object, prim)) {
+ continue;
+ }
+ int object_flag = kernel_tex_fetch(__object_flag, prim_object);
+ if ((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
+ continue;
+ }
+ motion_triangle_intersect(kg,
+ isect,
+ P,
+ dir,
+ isect->t,
+ ray->time,
+ visibility,
+ prim_object,
+ prim,
+ prim_addr);
+ }
+ break;
+ }
+#endif
+ default: {
+ break;
+ }
+ }
+ }
+ else {
+ /* instance push */
+ object = kernel_tex_fetch(__prim_object, -prim_addr - 1);
+ int object_flag = kernel_tex_fetch(__object_flag, object);
+ if (object_flag & SD_OBJECT_HAS_VOLUME) {
+#if BVH_FEATURE(BVH_MOTION)
+ isect->t *= bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &ob_itfm);
+#else
+ isect->t *= bvh_instance_push(kg, object, ray, &P, &dir, &idir);
+#endif
+
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_STACK_SIZE);
+ traversal_stack[stack_ptr] = ENTRYPOINT_SENTINEL;
+
+ node_addr = kernel_tex_fetch(__object_node, object);
+ }
+ else {
+ /* pop */
+ object = OBJECT_NONE;
+ node_addr = traversal_stack[stack_ptr];
+ --stack_ptr;
+ }
+ }
+ }
+ } while (node_addr != ENTRYPOINT_SENTINEL);
+
+ if (stack_ptr >= 0) {
+ kernel_assert(object != OBJECT_NONE);
+
+ /* instance pop */
+#if BVH_FEATURE(BVH_MOTION)
+ isect->t = bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir, isect->t, &ob_itfm);
+#else
+ isect->t = bvh_instance_pop(kg, object, ray, &P, &dir, &idir, isect->t);
+#endif
+
+ object = OBJECT_NONE;
+ node_addr = traversal_stack[stack_ptr];
+ --stack_ptr;
+ }
+ } while (node_addr != ENTRYPOINT_SENTINEL);
+
+ return (isect->prim != PRIM_NONE);
+}
+
+ccl_device_inline bool BVH_FUNCTION_NAME(KernelGlobals kg,
+ ccl_private const Ray *ray,
+ ccl_private Intersection *isect,
+ const uint visibility)
+{
+ return BVH_FUNCTION_FULL_NAME(BVH)(kg, ray, isect, visibility);
+}
+
+#undef BVH_FUNCTION_NAME
+#undef BVH_FUNCTION_FEATURES
+#undef NODE_INTERSECT
diff --git a/intern/cycles/kernel/bvh/volume_all.h b/intern/cycles/kernel/bvh/volume_all.h
new file mode 100644
index 00000000000..9f53e987cf1
--- /dev/null
+++ b/intern/cycles/kernel/bvh/volume_all.h
@@ -0,0 +1,319 @@
+/*
+ * Adapted from code Copyright 2009-2010 NVIDIA Corporation,
+ * and code copyright 2009-2012 Intel Corporation
+ *
+ * Modifications 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.
+ */
+
+#if BVH_FEATURE(BVH_HAIR)
+# define NODE_INTERSECT bvh_node_intersect
+#else
+# define NODE_INTERSECT bvh_aligned_node_intersect
+#endif
+
+/* This is a template BVH traversal function for volumes, where
+ * various features can be enabled/disabled. This way we can compile optimized
+ * versions for each case without new features slowing things down.
+ *
+ * BVH_MOTION: motion blur rendering
+ */
+
+#ifndef __KERNEL_GPU__
+ccl_device
+#else
+ccl_device_inline
+#endif
+ uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals kg,
+ ccl_private const Ray *ray,
+ Intersection *isect_array,
+ const uint max_hits,
+ const uint visibility)
+{
+ /* todo:
+ * - test if pushing distance on the stack helps (for non shadow rays)
+ * - separate version for shadow rays
+ * - likely and unlikely for if() statements
+ * - test restrict attribute for pointers
+ */
+
+ /* traversal stack in CUDA thread-local memory */
+ int traversal_stack[BVH_STACK_SIZE];
+ traversal_stack[0] = ENTRYPOINT_SENTINEL;
+
+ /* traversal variables in registers */
+ int stack_ptr = 0;
+ int node_addr = kernel_data.bvh.root;
+
+ /* ray parameters in registers */
+ const float tmax = ray->t;
+ float3 P = ray->P;
+ float3 dir = bvh_clamp_direction(ray->D);
+ float3 idir = bvh_inverse_direction(dir);
+ int object = OBJECT_NONE;
+ float isect_t = tmax;
+
+#if BVH_FEATURE(BVH_MOTION)
+ Transform ob_itfm;
+#endif
+
+ int num_hits_in_instance = 0;
+
+ uint num_hits = 0;
+ isect_array->t = tmax;
+
+ /* traversal loop */
+ do {
+ do {
+ /* traverse internal nodes */
+ while (node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) {
+ int node_addr_child1, traverse_mask;
+ float dist[2];
+ float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr + 0);
+
+ traverse_mask = NODE_INTERSECT(kg,
+ P,
+#if BVH_FEATURE(BVH_HAIR)
+ dir,
+#endif
+ idir,
+ isect_t,
+ node_addr,
+ visibility,
+ dist);
+
+ node_addr = __float_as_int(cnodes.z);
+ node_addr_child1 = __float_as_int(cnodes.w);
+
+ if (traverse_mask == 3) {
+ /* Both children were intersected, push the farther one. */
+ bool is_closest_child1 = (dist[1] < dist[0]);
+ if (is_closest_child1) {
+ int tmp = node_addr;
+ node_addr = node_addr_child1;
+ node_addr_child1 = tmp;
+ }
+
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_STACK_SIZE);
+ traversal_stack[stack_ptr] = node_addr_child1;
+ }
+ else {
+ /* One child was intersected. */
+ if (traverse_mask == 2) {
+ node_addr = node_addr_child1;
+ }
+ else if (traverse_mask == 0) {
+ /* Neither child was intersected. */
+ node_addr = traversal_stack[stack_ptr];
+ --stack_ptr;
+ }
+ }
+ }
+
+ /* if node is leaf, fetch triangle list */
+ if (node_addr < 0) {
+ float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr - 1));
+ int prim_addr = __float_as_int(leaf.x);
+
+ if (prim_addr >= 0) {
+ const int prim_addr2 = __float_as_int(leaf.y);
+ const uint type = __float_as_int(leaf.w);
+ bool hit;
+
+ /* pop */
+ node_addr = traversal_stack[stack_ptr];
+ --stack_ptr;
+
+ /* primitive intersection */
+ switch (type & PRIMITIVE_ALL) {
+ case PRIMITIVE_TRIANGLE: {
+ /* intersect ray against primitive */
+ for (; prim_addr < prim_addr2; prim_addr++) {
+ kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
+ /* only primitives from volume object */
+ const int prim_object = (object == OBJECT_NONE) ?
+ kernel_tex_fetch(__prim_object, prim_addr) :
+ object;
+ const int prim = kernel_tex_fetch(__prim_index, prim_addr);
+ if (intersection_skip_self(ray->self, prim_object, prim)) {
+ continue;
+ }
+ int object_flag = kernel_tex_fetch(__object_flag, prim_object);
+ if ((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
+ continue;
+ }
+ hit = triangle_intersect(
+ kg, isect_array, P, dir, isect_t, visibility, prim_object, prim, prim_addr);
+ if (hit) {
+ /* Move on to next entry in intersections array. */
+ isect_array++;
+ num_hits++;
+ num_hits_in_instance++;
+ isect_array->t = isect_t;
+ if (num_hits == max_hits) {
+ if (object != OBJECT_NONE) {
+#if BVH_FEATURE(BVH_MOTION)
+ float t_fac = 1.0f / len(transform_direction(&ob_itfm, dir));
+#else
+ Transform itfm = object_fetch_transform(
+ kg, object, OBJECT_INVERSE_TRANSFORM);
+ float t_fac = 1.0f / len(transform_direction(&itfm, dir));
+#endif
+ for (int i = 0; i < num_hits_in_instance; i++) {
+ (isect_array - i - 1)->t *= t_fac;
+ }
+ }
+ return num_hits;
+ }
+ }
+ }
+ break;
+ }
+#if BVH_FEATURE(BVH_MOTION)
+ case PRIMITIVE_MOTION_TRIANGLE: {
+ /* intersect ray against primitive */
+ for (; prim_addr < prim_addr2; prim_addr++) {
+ kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
+ /* only primitives from volume object */
+ const int prim_object = (object == OBJECT_NONE) ?
+ kernel_tex_fetch(__prim_object, prim_addr) :
+ object;
+ const int prim = kernel_tex_fetch(__prim_index, prim_addr);
+ if (intersection_skip_self(ray->self, prim_object, prim)) {
+ continue;
+ }
+ int object_flag = kernel_tex_fetch(__object_flag, prim_object);
+ if ((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
+ continue;
+ }
+ hit = motion_triangle_intersect(kg,
+ isect_array,
+ P,
+ dir,
+ isect_t,
+ ray->time,
+ visibility,
+ prim_object,
+ prim,
+ prim_addr);
+ if (hit) {
+ /* Move on to next entry in intersections array. */
+ isect_array++;
+ num_hits++;
+ num_hits_in_instance++;
+ isect_array->t = isect_t;
+ if (num_hits == max_hits) {
+ if (object != OBJECT_NONE) {
+# if BVH_FEATURE(BVH_MOTION)
+ float t_fac = 1.0f / len(transform_direction(&ob_itfm, dir));
+# else
+ Transform itfm = object_fetch_transform(
+ kg, object, OBJECT_INVERSE_TRANSFORM);
+ float t_fac = 1.0f / len(transform_direction(&itfm, dir));
+# endif
+ for (int i = 0; i < num_hits_in_instance; i++) {
+ (isect_array - i - 1)->t *= t_fac;
+ }
+ }
+ return num_hits;
+ }
+ }
+ }
+ break;
+ }
+#endif /* BVH_MOTION */
+ default: {
+ break;
+ }
+ }
+ }
+ else {
+ /* instance push */
+ object = kernel_tex_fetch(__prim_object, -prim_addr - 1);
+ int object_flag = kernel_tex_fetch(__object_flag, object);
+ if (object_flag & SD_OBJECT_HAS_VOLUME) {
+#if BVH_FEATURE(BVH_MOTION)
+ isect_t *= bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &ob_itfm);
+#else
+ isect_t *= bvh_instance_push(kg, object, ray, &P, &dir, &idir);
+#endif
+
+ num_hits_in_instance = 0;
+ isect_array->t = isect_t;
+
+ ++stack_ptr;
+ kernel_assert(stack_ptr < BVH_STACK_SIZE);
+ traversal_stack[stack_ptr] = ENTRYPOINT_SENTINEL;
+
+ node_addr = kernel_tex_fetch(__object_node, object);
+ }
+ else {
+ /* pop */
+ object = OBJECT_NONE;
+ node_addr = traversal_stack[stack_ptr];
+ --stack_ptr;
+ }
+ }
+ }
+ } while (node_addr != ENTRYPOINT_SENTINEL);
+
+ if (stack_ptr >= 0) {
+ kernel_assert(object != OBJECT_NONE);
+
+ /* Instance pop. */
+ if (num_hits_in_instance) {
+ float t_fac;
+#if BVH_FEATURE(BVH_MOTION)
+ bvh_instance_motion_pop_factor(kg, object, ray, &P, &dir, &idir, &t_fac, &ob_itfm);
+#else
+ bvh_instance_pop_factor(kg, object, ray, &P, &dir, &idir, &t_fac);
+#endif
+ /* Scale isect->t to adjust for instancing. */
+ for (int i = 0; i < num_hits_in_instance; i++) {
+ (isect_array - i - 1)->t *= t_fac;
+ }
+ }
+ else {
+#if BVH_FEATURE(BVH_MOTION)
+ bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir, FLT_MAX, &ob_itfm);
+#else
+ bvh_instance_pop(kg, object, ray, &P, &dir, &idir, FLT_MAX);
+#endif
+ }
+
+ isect_t = tmax;
+ isect_array->t = isect_t;
+
+ object = OBJECT_NONE;
+ node_addr = traversal_stack[stack_ptr];
+ --stack_ptr;
+ }
+ } while (node_addr != ENTRYPOINT_SENTINEL);
+
+ return num_hits;
+}
+
+ccl_device_inline uint BVH_FUNCTION_NAME(KernelGlobals kg,
+ ccl_private const Ray *ray,
+ Intersection *isect_array,
+ const uint max_hits,
+ const uint visibility)
+{
+ return BVH_FUNCTION_FULL_NAME(BVH)(kg, ray, isect_array, max_hits, visibility);
+}
+
+#undef BVH_FUNCTION_NAME
+#undef BVH_FUNCTION_FEATURES
+#undef NODE_INTERSECT
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/camera/projection.h b/intern/cycles/kernel/camera/projection.h
new file mode 100644
index 00000000000..7b4e23e4ed0
--- /dev/null
+++ b/intern/cycles/kernel/camera/projection.h
@@ -0,0 +1,315 @@
+/*
+ * 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
+
+/* Spherical coordinates <-> Cartesian direction. */
+
+ccl_device float2 direction_to_spherical(float3 dir)
+{
+ float theta = safe_acosf(dir.z);
+ float phi = atan2f(dir.x, dir.y);
+
+ return make_float2(theta, phi);
+}
+
+ccl_device float3 spherical_to_direction(float theta, float phi)
+{
+ float sin_theta = sinf(theta);
+ return make_float3(sin_theta * cosf(phi), sin_theta * sinf(phi), cosf(theta));
+}
+
+/* Equirectangular coordinates <-> Cartesian direction */
+
+ccl_device float2 direction_to_equirectangular_range(float3 dir, float4 range)
+{
+ if (is_zero(dir))
+ return zero_float2();
+
+ float u = (atan2f(dir.y, dir.x) - range.y) / range.x;
+ float v = (acosf(dir.z / len(dir)) - range.w) / range.z;
+
+ return make_float2(u, v);
+}
+
+ccl_device float3 equirectangular_range_to_direction(float u, float v, float4 range)
+{
+ float phi = range.x * u + range.y;
+ float theta = range.z * v + range.w;
+ float sin_theta = sinf(theta);
+ return make_float3(sin_theta * cosf(phi), sin_theta * sinf(phi), cosf(theta));
+}
+
+ccl_device float2 direction_to_equirectangular(float3 dir)
+{
+ return direction_to_equirectangular_range(dir, make_float4(-M_2PI_F, M_PI_F, -M_PI_F, M_PI_F));
+}
+
+ccl_device float3 equirectangular_to_direction(float u, float v)
+{
+ return equirectangular_range_to_direction(u, v, make_float4(-M_2PI_F, M_PI_F, -M_PI_F, M_PI_F));
+}
+
+/* Fisheye <-> Cartesian direction */
+
+ccl_device float2 direction_to_fisheye(float3 dir, float fov)
+{
+ float r = atan2f(sqrtf(dir.y * dir.y + dir.z * dir.z), dir.x) / fov;
+ float phi = atan2f(dir.z, dir.y);
+
+ float u = r * cosf(phi) + 0.5f;
+ float v = r * sinf(phi) + 0.5f;
+
+ return make_float2(u, v);
+}
+
+ccl_device float3 fisheye_to_direction(float u, float v, float fov)
+{
+ u = (u - 0.5f) * 2.0f;
+ v = (v - 0.5f) * 2.0f;
+
+ float r = sqrtf(u * u + v * v);
+
+ if (r > 1.0f)
+ return zero_float3();
+
+ float phi = safe_acosf((r != 0.0f) ? u / r : 0.0f);
+ float theta = r * fov * 0.5f;
+
+ if (v < 0.0f)
+ phi = -phi;
+
+ return make_float3(cosf(theta), -cosf(phi) * sinf(theta), sinf(phi) * sinf(theta));
+}
+
+ccl_device float2 direction_to_fisheye_equisolid(float3 dir, float lens, float width, float height)
+{
+ float theta = safe_acosf(dir.x);
+ float r = 2.0f * lens * sinf(theta * 0.5f);
+ float phi = atan2f(dir.z, dir.y);
+
+ float u = r * cosf(phi) / width + 0.5f;
+ float v = r * sinf(phi) / height + 0.5f;
+
+ return make_float2(u, v);
+}
+
+ccl_device_inline float3
+fisheye_equisolid_to_direction(float u, float v, float lens, float fov, float width, float height)
+{
+ u = (u - 0.5f) * width;
+ v = (v - 0.5f) * height;
+
+ float rmax = 2.0f * lens * sinf(fov * 0.25f);
+ float r = sqrtf(u * u + v * v);
+
+ if (r > rmax)
+ return zero_float3();
+
+ float phi = safe_acosf((r != 0.0f) ? u / r : 0.0f);
+ float theta = 2.0f * asinf(r / (2.0f * lens));
+
+ if (v < 0.0f)
+ phi = -phi;
+
+ return make_float3(cosf(theta), -cosf(phi) * sinf(theta), sinf(phi) * sinf(theta));
+}
+
+ccl_device_inline float3 fisheye_lens_polynomial_to_direction(
+ float u, float v, float coeff0, float4 coeffs, float fov, float width, float height)
+{
+ u = (u - 0.5f) * width;
+ v = (v - 0.5f) * height;
+
+ float r = sqrtf(u * u + v * v);
+ float r2 = r * r;
+ float4 rr = make_float4(r, r2, r2 * r, r2 * r2);
+ float theta = -(coeff0 + dot(coeffs, rr));
+
+ if (fabsf(theta) > 0.5f * fov)
+ return zero_float3();
+
+ float phi = safe_acosf((r != 0.0f) ? u / r : 0.0f);
+
+ if (v < 0.0f)
+ phi = -phi;
+
+ return make_float3(cosf(theta), -cosf(phi) * sinf(theta), sinf(phi) * sinf(theta));
+}
+
+ccl_device float2 direction_to_fisheye_lens_polynomial(
+ float3 dir, float coeff0, float4 coeffs, float width, float height)
+{
+ float theta = -safe_acosf(dir.x);
+
+ float r = (theta - coeff0) / coeffs.x;
+
+ for (int i = 0; i < 20; i++) {
+ float r2 = r * r;
+ float4 rr = make_float4(r, r2, r2 * r, r2 * r2);
+ r = (theta - (coeff0 + dot(coeffs, rr))) / coeffs.x;
+ }
+
+ float phi = atan2f(dir.z, dir.y);
+
+ float u = r * cosf(phi) / width + 0.5f;
+ float v = r * sinf(phi) / height + 0.5f;
+
+ return make_float2(u, v);
+}
+
+/* Mirror Ball <-> Cartesion direction */
+
+ccl_device float3 mirrorball_to_direction(float u, float v)
+{
+ /* point on sphere */
+ float3 dir;
+
+ dir.x = 2.0f * u - 1.0f;
+ dir.z = 2.0f * v - 1.0f;
+
+ if (dir.x * dir.x + dir.z * dir.z > 1.0f)
+ return zero_float3();
+
+ dir.y = -sqrtf(max(1.0f - dir.x * dir.x - dir.z * dir.z, 0.0f));
+
+ /* reflection */
+ float3 I = make_float3(0.0f, -1.0f, 0.0f);
+
+ return 2.0f * dot(dir, I) * dir - I;
+}
+
+ccl_device float2 direction_to_mirrorball(float3 dir)
+{
+ /* inverse of mirrorball_to_direction */
+ dir.y -= 1.0f;
+
+ float div = 2.0f * sqrtf(max(-0.5f * dir.y, 0.0f));
+ if (div > 0.0f)
+ dir /= div;
+
+ float u = 0.5f * (dir.x + 1.0f);
+ float v = 0.5f * (dir.z + 1.0f);
+
+ return make_float2(u, v);
+}
+
+ccl_device_inline float3 panorama_to_direction(ccl_constant KernelCamera *cam, float u, float v)
+{
+ switch (cam->panorama_type) {
+ case PANORAMA_EQUIRECTANGULAR:
+ return equirectangular_range_to_direction(u, v, cam->equirectangular_range);
+ case PANORAMA_MIRRORBALL:
+ return mirrorball_to_direction(u, v);
+ case PANORAMA_FISHEYE_EQUIDISTANT:
+ return fisheye_to_direction(u, v, cam->fisheye_fov);
+ case PANORAMA_FISHEYE_LENS_POLYNOMIAL:
+ return fisheye_lens_polynomial_to_direction(u,
+ v,
+ cam->fisheye_lens_polynomial_bias,
+ cam->fisheye_lens_polynomial_coefficients,
+ cam->fisheye_fov,
+ cam->sensorwidth,
+ cam->sensorheight);
+ case PANORAMA_FISHEYE_EQUISOLID:
+ default:
+ return fisheye_equisolid_to_direction(
+ u, v, cam->fisheye_lens, cam->fisheye_fov, cam->sensorwidth, cam->sensorheight);
+ }
+}
+
+ccl_device_inline float2 direction_to_panorama(ccl_constant KernelCamera *cam, float3 dir)
+{
+ switch (cam->panorama_type) {
+ case PANORAMA_EQUIRECTANGULAR:
+ return direction_to_equirectangular_range(dir, cam->equirectangular_range);
+ case PANORAMA_MIRRORBALL:
+ return direction_to_mirrorball(dir);
+ case PANORAMA_FISHEYE_EQUIDISTANT:
+ return direction_to_fisheye(dir, cam->fisheye_fov);
+ case PANORAMA_FISHEYE_LENS_POLYNOMIAL:
+ return direction_to_fisheye_lens_polynomial(dir,
+ cam->fisheye_lens_polynomial_bias,
+ cam->fisheye_lens_polynomial_coefficients,
+ cam->sensorwidth,
+ cam->sensorheight);
+ case PANORAMA_FISHEYE_EQUISOLID:
+ default:
+ return direction_to_fisheye_equisolid(
+ dir, cam->fisheye_lens, cam->sensorwidth, cam->sensorheight);
+ }
+}
+
+ccl_device_inline void spherical_stereo_transform(ccl_constant KernelCamera *cam,
+ ccl_private float3 *P,
+ ccl_private float3 *D)
+{
+ float interocular_offset = cam->interocular_offset;
+
+ /* Interocular offset of zero means either non stereo, or stereo without
+ * spherical stereo. */
+ kernel_assert(interocular_offset != 0.0f);
+
+ if (cam->pole_merge_angle_to > 0.0f) {
+ const float pole_merge_angle_from = cam->pole_merge_angle_from,
+ pole_merge_angle_to = cam->pole_merge_angle_to;
+ float altitude = fabsf(safe_asinf((*D).z));
+ if (altitude > pole_merge_angle_to) {
+ interocular_offset = 0.0f;
+ }
+ else if (altitude > pole_merge_angle_from) {
+ float fac = (altitude - pole_merge_angle_from) /
+ (pole_merge_angle_to - pole_merge_angle_from);
+ float fade = cosf(fac * M_PI_2_F);
+ interocular_offset *= fade;
+ }
+ }
+
+ float3 up = make_float3(0.0f, 0.0f, 1.0f);
+ float3 side = normalize(cross(*D, up));
+ float3 stereo_offset = side * interocular_offset;
+
+ *P += stereo_offset;
+
+ /* Convergence distance is FLT_MAX in the case of parallel convergence mode,
+ * no need to modify direction in this case either. */
+ const float convergence_distance = cam->convergence_distance;
+
+ if (convergence_distance != FLT_MAX) {
+ float3 screen_offset = convergence_distance * (*D);
+ *D = normalize(screen_offset - stereo_offset);
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/closure/alloc.h b/intern/cycles/kernel/closure/alloc.h
index 72a8c2ba090..211eedbddbd 100644
--- a/intern/cycles/kernel/closure/alloc.h
+++ b/intern/cycles/kernel/closure/alloc.h
@@ -18,14 +18,17 @@
CCL_NAMESPACE_BEGIN
-ccl_device ShaderClosure *closure_alloc(ShaderData *sd, int size, ClosureType type, float3 weight)
+ccl_device ccl_private ShaderClosure *closure_alloc(ccl_private ShaderData *sd,
+ int size,
+ ClosureType type,
+ float3 weight)
{
kernel_assert(size <= sizeof(ShaderClosure));
if (sd->num_closure_left == 0)
return NULL;
- ShaderClosure *sc = &sd->closure[sd->num_closure];
+ ccl_private ShaderClosure *sc = &sd->closure[sd->num_closure];
sc->type = type;
sc->weight = weight;
@@ -36,7 +39,7 @@ ccl_device ShaderClosure *closure_alloc(ShaderData *sd, int size, ClosureType ty
return sc;
}
-ccl_device ccl_addr_space void *closure_alloc_extra(ShaderData *sd, int size)
+ccl_device ccl_private void *closure_alloc_extra(ccl_private ShaderData *sd, int size)
{
/* Allocate extra space for closure that need more parameters. We allocate
* in chunks of sizeof(ShaderClosure) starting from the end of the closure
@@ -54,10 +57,12 @@ ccl_device ccl_addr_space void *closure_alloc_extra(ShaderData *sd, int size)
}
sd->num_closure_left -= num_extra;
- return (ccl_addr_space void *)(sd->closure + sd->num_closure + sd->num_closure_left);
+ return (ccl_private void *)(sd->closure + sd->num_closure + sd->num_closure_left);
}
-ccl_device_inline ShaderClosure *bsdf_alloc(ShaderData *sd, int size, float3 weight)
+ccl_device_inline ccl_private ShaderClosure *bsdf_alloc(ccl_private ShaderData *sd,
+ int size,
+ float3 weight)
{
kernel_assert(isfinite3_safe(weight));
@@ -66,7 +71,7 @@ ccl_device_inline ShaderClosure *bsdf_alloc(ShaderData *sd, int size, float3 wei
/* Use comparison this way to help dealing with non-finite weight: if the average is not finite
* we will not allocate new closure. */
if (sample_weight >= CLOSURE_WEIGHT_CUTOFF) {
- ShaderClosure *sc = closure_alloc(sd, size, CLOSURE_NONE_ID, weight);
+ ccl_private ShaderClosure *sc = closure_alloc(sd, size, CLOSURE_NONE_ID, weight);
if (sc == NULL) {
return NULL;
}
diff --git a/intern/cycles/kernel/closure/bsdf.h b/intern/cycles/kernel/closure/bsdf.h
index 4eb8bcae997..2c8ef858270 100644
--- a/intern/cycles/kernel/closure/bsdf.h
+++ b/intern/cycles/kernel/closure/bsdf.h
@@ -41,32 +41,32 @@ CCL_NAMESPACE_BEGIN
/* Returns the square of the roughness of the closure if it has roughness,
* 0 for singular closures and 1 otherwise. */
-ccl_device_inline float bsdf_get_specular_roughness_squared(const ShaderClosure *sc)
+ccl_device_inline float bsdf_get_specular_roughness_squared(ccl_private const ShaderClosure *sc)
{
if (CLOSURE_IS_BSDF_SINGULAR(sc->type)) {
return 0.0f;
}
if (CLOSURE_IS_BSDF_MICROFACET(sc->type)) {
- MicrofacetBsdf *bsdf = (MicrofacetBsdf *)sc;
+ ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)sc;
return bsdf->alpha_x * bsdf->alpha_y;
}
return 1.0f;
}
-ccl_device_inline float bsdf_get_roughness_squared(const ShaderClosure *sc)
+ccl_device_inline float bsdf_get_roughness_squared(ccl_private const ShaderClosure *sc)
{
/* This version includes diffuse, mainly for baking Principled BSDF
* where specular and metallic zero otherwise does not bake the
* specified roughness parameter. */
if (sc->type == CLOSURE_BSDF_OREN_NAYAR_ID) {
- OrenNayarBsdf *bsdf = (OrenNayarBsdf *)sc;
+ ccl_private OrenNayarBsdf *bsdf = (ccl_private OrenNayarBsdf *)sc;
return sqr(sqr(bsdf->roughness));
}
if (sc->type == CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID) {
- PrincipledDiffuseBsdf *bsdf = (PrincipledDiffuseBsdf *)sc;
+ ccl_private PrincipledDiffuseBsdf *bsdf = (ccl_private PrincipledDiffuseBsdf *)sc;
return sqr(sqr(bsdf->roughness));
}
@@ -111,24 +111,23 @@ ccl_device_inline float shift_cos_in(float cos_in, const float frequency_multipl
return val;
}
-ccl_device_inline int bsdf_sample(const KernelGlobals *kg,
- ShaderData *sd,
- const ShaderClosure *sc,
+ccl_device_inline int bsdf_sample(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private const ShaderClosure *sc,
float randu,
float randv,
- float3 *eval,
- float3 *omega_in,
- differential3 *domega_in,
- float *pdf)
+ ccl_private float3 *eval,
+ ccl_private float3 *omega_in,
+ ccl_private differential3 *domega_in,
+ ccl_private float *pdf)
{
/* For curves use the smooth normal, particularly for ribbons the geometric
* normal gives too much darkening otherwise. */
int label;
- const float3 Ng = (sd->type & PRIMITIVE_ALL_CURVE) ? sc->N : sd->Ng;
+ const float3 Ng = (sd->type & PRIMITIVE_CURVE) ? sc->N : sd->Ng;
switch (sc->type) {
case CLOSURE_BSDF_DIFFUSE_ID:
- case CLOSURE_BSDF_BSSRDF_ID:
label = bsdf_diffuse_sample(sc,
Ng,
sd->I,
@@ -401,7 +400,6 @@ ccl_device_inline int bsdf_sample(const KernelGlobals *kg,
break;
# ifdef __PRINCIPLED__
case CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID:
- case CLOSURE_BSDF_BSSRDF_PRINCIPLED_ID:
label = bsdf_principled_diffuse_sample(sc,
Ng,
sd->I,
@@ -440,7 +438,7 @@ ccl_device_inline int bsdf_sample(const KernelGlobals *kg,
if (label & LABEL_TRANSMIT) {
float threshold_squared = kernel_data.background.transparent_roughness_squared_threshold;
- if (threshold_squared >= 0.0f) {
+ if (threshold_squared >= 0.0f && !(label & LABEL_DIFFUSE)) {
if (bsdf_get_specular_roughness_squared(sc) <= threshold_squared) {
label |= LABEL_TRANSMIT_TRANSPARENT;
}
@@ -469,19 +467,18 @@ ccl_device
ccl_device_inline
#endif
float3
- bsdf_eval(const KernelGlobals *kg,
- ShaderData *sd,
- const ShaderClosure *sc,
+ bsdf_eval(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private const ShaderClosure *sc,
const float3 omega_in,
const bool is_transmission,
- float *pdf)
+ ccl_private float *pdf)
{
float3 eval = zero_float3();
if (!is_transmission) {
switch (sc->type) {
case CLOSURE_BSDF_DIFFUSE_ID:
- case CLOSURE_BSDF_BSSRDF_ID:
eval = bsdf_diffuse_eval_reflect(sc, sd->I, omega_in, pdf);
break;
#ifdef __SVM__
@@ -550,7 +547,6 @@ ccl_device_inline
break;
# ifdef __PRINCIPLED__
case CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID:
- case CLOSURE_BSDF_BSSRDF_PRINCIPLED_ID:
eval = bsdf_principled_diffuse_eval_reflect(sc, sd->I, omega_in, pdf);
break;
case CLOSURE_BSDF_PRINCIPLED_SHEEN_ID:
@@ -576,7 +572,6 @@ ccl_device_inline
else {
switch (sc->type) {
case CLOSURE_BSDF_DIFFUSE_ID:
- case CLOSURE_BSDF_BSSRDF_ID:
eval = bsdf_diffuse_eval_transmit(sc, sd->I, omega_in, pdf);
break;
#ifdef __SVM__
@@ -637,7 +632,6 @@ ccl_device_inline
break;
# ifdef __PRINCIPLED__
case CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID:
- case CLOSURE_BSDF_BSSRDF_PRINCIPLED_ID:
eval = bsdf_principled_diffuse_eval_transmit(sc, sd->I, omega_in, pdf);
break;
case CLOSURE_BSDF_PRINCIPLED_SHEEN_ID:
@@ -658,9 +652,9 @@ ccl_device_inline
return eval;
}
-ccl_device void bsdf_blur(const KernelGlobals *kg, ShaderClosure *sc, float roughness)
+ccl_device void bsdf_blur(KernelGlobals kg, ccl_private ShaderClosure *sc, float roughness)
{
- /* ToDo: do we want to blur volume closures? */
+ /* TODO: do we want to blur volume closures? */
#ifdef __SVM__
switch (sc->type) {
case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID:
diff --git a/intern/cycles/kernel/closure/bsdf_ashikhmin_shirley.h b/intern/cycles/kernel/closure/bsdf_ashikhmin_shirley.h
index be6383e521a..6cd8739ce39 100644
--- a/intern/cycles/kernel/closure/bsdf_ashikhmin_shirley.h
+++ b/intern/cycles/kernel/closure/bsdf_ashikhmin_shirley.h
@@ -30,7 +30,7 @@
CCL_NAMESPACE_BEGIN
-ccl_device int bsdf_ashikhmin_shirley_setup(MicrofacetBsdf *bsdf)
+ccl_device int bsdf_ashikhmin_shirley_setup(ccl_private MicrofacetBsdf *bsdf)
{
bsdf->alpha_x = clamp(bsdf->alpha_x, 1e-4f, 1.0f);
bsdf->alpha_y = clamp(bsdf->alpha_y, 1e-4f, 1.0f);
@@ -39,9 +39,9 @@ ccl_device int bsdf_ashikhmin_shirley_setup(MicrofacetBsdf *bsdf)
return SD_BSDF | SD_BSDF_HAS_EVAL;
}
-ccl_device void bsdf_ashikhmin_shirley_blur(ShaderClosure *sc, float roughness)
+ccl_device void bsdf_ashikhmin_shirley_blur(ccl_private ShaderClosure *sc, float roughness)
{
- MicrofacetBsdf *bsdf = (MicrofacetBsdf *)sc;
+ ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)sc;
bsdf->alpha_x = fmaxf(roughness, bsdf->alpha_x);
bsdf->alpha_y = fmaxf(roughness, bsdf->alpha_y);
@@ -52,12 +52,13 @@ ccl_device_inline float bsdf_ashikhmin_shirley_roughness_to_exponent(float rough
return 2.0f / (roughness * roughness) - 2.0f;
}
-ccl_device_forceinline float3 bsdf_ashikhmin_shirley_eval_reflect(const ShaderClosure *sc,
- const float3 I,
- const float3 omega_in,
- float *pdf)
+ccl_device_forceinline float3
+bsdf_ashikhmin_shirley_eval_reflect(ccl_private const ShaderClosure *sc,
+ const float3 I,
+ const float3 omega_in,
+ ccl_private float *pdf)
{
- const MicrofacetBsdf *bsdf = (const MicrofacetBsdf *)sc;
+ ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc;
float3 N = bsdf->N;
float NdotI = dot(N, I); /* in Cycles/OSL convention I is omega_out */
@@ -119,16 +120,20 @@ ccl_device_forceinline float3 bsdf_ashikhmin_shirley_eval_reflect(const ShaderCl
return make_float3(out, out, out);
}
-ccl_device float3 bsdf_ashikhmin_shirley_eval_transmit(const ShaderClosure *sc,
+ccl_device float3 bsdf_ashikhmin_shirley_eval_transmit(ccl_private const ShaderClosure *sc,
const float3 I,
const float3 omega_in,
- float *pdf)
+ ccl_private float *pdf)
{
return make_float3(0.0f, 0.0f, 0.0f);
}
-ccl_device_inline void bsdf_ashikhmin_shirley_sample_first_quadrant(
- float n_x, float n_y, float randu, float randv, float *phi, float *cos_theta)
+ccl_device_inline void bsdf_ashikhmin_shirley_sample_first_quadrant(float n_x,
+ float n_y,
+ float randu,
+ float randv,
+ ccl_private float *phi,
+ ccl_private float *cos_theta)
{
*phi = atanf(sqrtf((n_x + 1.0f) / (n_y + 1.0f)) * tanf(M_PI_2_F * randu));
float cos_phi = cosf(*phi);
@@ -136,20 +141,20 @@ ccl_device_inline void bsdf_ashikhmin_shirley_sample_first_quadrant(
*cos_theta = powf(randv, 1.0f / (n_x * cos_phi * cos_phi + n_y * sin_phi * sin_phi + 1.0f));
}
-ccl_device int bsdf_ashikhmin_shirley_sample(const ShaderClosure *sc,
+ccl_device int bsdf_ashikhmin_shirley_sample(ccl_private const ShaderClosure *sc,
float3 Ng,
float3 I,
float3 dIdx,
float3 dIdy,
float randu,
float randv,
- float3 *eval,
- float3 *omega_in,
- float3 *domega_in_dx,
- float3 *domega_in_dy,
- float *pdf)
+ ccl_private float3 *eval,
+ ccl_private float3 *omega_in,
+ ccl_private float3 *domega_in_dx,
+ ccl_private float3 *domega_in_dy,
+ ccl_private float *pdf)
{
- const MicrofacetBsdf *bsdf = (const MicrofacetBsdf *)sc;
+ ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc;
float3 N = bsdf->N;
int label = LABEL_REFLECT | LABEL_GLOSSY;
diff --git a/intern/cycles/kernel/closure/bsdf_ashikhmin_velvet.h b/intern/cycles/kernel/closure/bsdf_ashikhmin_velvet.h
index f51027f5701..b2a9c9555c3 100644
--- a/intern/cycles/kernel/closure/bsdf_ashikhmin_velvet.h
+++ b/intern/cycles/kernel/closure/bsdf_ashikhmin_velvet.h
@@ -32,11 +32,11 @@
#pragma once
-#include "kernel/kernel_montecarlo.h"
+#include "kernel/sample/mapping.h"
CCL_NAMESPACE_BEGIN
-typedef ccl_addr_space struct VelvetBsdf {
+typedef struct VelvetBsdf {
SHADER_CLOSURE_BASE;
float sigma;
@@ -45,7 +45,7 @@ typedef ccl_addr_space struct VelvetBsdf {
static_assert(sizeof(ShaderClosure) >= sizeof(VelvetBsdf), "VelvetBsdf is too large!");
-ccl_device int bsdf_ashikhmin_velvet_setup(VelvetBsdf *bsdf)
+ccl_device int bsdf_ashikhmin_velvet_setup(ccl_private VelvetBsdf *bsdf)
{
float sigma = fmaxf(bsdf->sigma, 0.01f);
bsdf->invsigma2 = 1.0f / (sigma * sigma);
@@ -55,12 +55,12 @@ ccl_device int bsdf_ashikhmin_velvet_setup(VelvetBsdf *bsdf)
return SD_BSDF | SD_BSDF_HAS_EVAL;
}
-ccl_device float3 bsdf_ashikhmin_velvet_eval_reflect(const ShaderClosure *sc,
+ccl_device float3 bsdf_ashikhmin_velvet_eval_reflect(ccl_private const ShaderClosure *sc,
const float3 I,
const float3 omega_in,
- float *pdf)
+ ccl_private float *pdf)
{
- const VelvetBsdf *bsdf = (const VelvetBsdf *)sc;
+ ccl_private const VelvetBsdf *bsdf = (ccl_private const VelvetBsdf *)sc;
float m_invsigma2 = bsdf->invsigma2;
float3 N = bsdf->N;
@@ -97,28 +97,28 @@ ccl_device float3 bsdf_ashikhmin_velvet_eval_reflect(const ShaderClosure *sc,
return make_float3(0.0f, 0.0f, 0.0f);
}
-ccl_device float3 bsdf_ashikhmin_velvet_eval_transmit(const ShaderClosure *sc,
+ccl_device float3 bsdf_ashikhmin_velvet_eval_transmit(ccl_private const ShaderClosure *sc,
const float3 I,
const float3 omega_in,
- float *pdf)
+ ccl_private float *pdf)
{
return make_float3(0.0f, 0.0f, 0.0f);
}
-ccl_device int bsdf_ashikhmin_velvet_sample(const ShaderClosure *sc,
+ccl_device int bsdf_ashikhmin_velvet_sample(ccl_private const ShaderClosure *sc,
float3 Ng,
float3 I,
float3 dIdx,
float3 dIdy,
float randu,
float randv,
- float3 *eval,
- float3 *omega_in,
- float3 *domega_in_dx,
- float3 *domega_in_dy,
- float *pdf)
+ ccl_private float3 *eval,
+ ccl_private float3 *omega_in,
+ ccl_private float3 *domega_in_dx,
+ ccl_private float3 *domega_in_dy,
+ ccl_private float *pdf)
{
- const VelvetBsdf *bsdf = (const VelvetBsdf *)sc;
+ ccl_private const VelvetBsdf *bsdf = (ccl_private const VelvetBsdf *)sc;
float m_invsigma2 = bsdf->invsigma2;
float3 N = bsdf->N;
diff --git a/intern/cycles/kernel/closure/bsdf_diffuse.h b/intern/cycles/kernel/closure/bsdf_diffuse.h
index 1555aa30304..3139cb612fa 100644
--- a/intern/cycles/kernel/closure/bsdf_diffuse.h
+++ b/intern/cycles/kernel/closure/bsdf_diffuse.h
@@ -32,9 +32,11 @@
#pragma once
+#include "kernel/sample/mapping.h"
+
CCL_NAMESPACE_BEGIN
-typedef ccl_addr_space struct DiffuseBsdf {
+typedef struct DiffuseBsdf {
SHADER_CLOSURE_BASE;
} DiffuseBsdf;
@@ -42,18 +44,18 @@ static_assert(sizeof(ShaderClosure) >= sizeof(DiffuseBsdf), "DiffuseBsdf is too
/* DIFFUSE */
-ccl_device int bsdf_diffuse_setup(DiffuseBsdf *bsdf)
+ccl_device int bsdf_diffuse_setup(ccl_private DiffuseBsdf *bsdf)
{
bsdf->type = CLOSURE_BSDF_DIFFUSE_ID;
return SD_BSDF | SD_BSDF_HAS_EVAL;
}
-ccl_device float3 bsdf_diffuse_eval_reflect(const ShaderClosure *sc,
+ccl_device float3 bsdf_diffuse_eval_reflect(ccl_private const ShaderClosure *sc,
const float3 I,
const float3 omega_in,
- float *pdf)
+ ccl_private float *pdf)
{
- const DiffuseBsdf *bsdf = (const DiffuseBsdf *)sc;
+ ccl_private const DiffuseBsdf *bsdf = (ccl_private const DiffuseBsdf *)sc;
float3 N = bsdf->N;
float cos_pi = fmaxf(dot(N, omega_in), 0.0f) * M_1_PI_F;
@@ -61,28 +63,28 @@ ccl_device float3 bsdf_diffuse_eval_reflect(const ShaderClosure *sc,
return make_float3(cos_pi, cos_pi, cos_pi);
}
-ccl_device float3 bsdf_diffuse_eval_transmit(const ShaderClosure *sc,
+ccl_device float3 bsdf_diffuse_eval_transmit(ccl_private const ShaderClosure *sc,
const float3 I,
const float3 omega_in,
- float *pdf)
+ ccl_private float *pdf)
{
return make_float3(0.0f, 0.0f, 0.0f);
}
-ccl_device int bsdf_diffuse_sample(const ShaderClosure *sc,
+ccl_device int bsdf_diffuse_sample(ccl_private const ShaderClosure *sc,
float3 Ng,
float3 I,
float3 dIdx,
float3 dIdy,
float randu,
float randv,
- float3 *eval,
- float3 *omega_in,
- float3 *domega_in_dx,
- float3 *domega_in_dy,
- float *pdf)
+ ccl_private float3 *eval,
+ ccl_private float3 *omega_in,
+ ccl_private float3 *domega_in_dx,
+ ccl_private float3 *domega_in_dy,
+ ccl_private float *pdf)
{
- const DiffuseBsdf *bsdf = (const DiffuseBsdf *)sc;
+ ccl_private const DiffuseBsdf *bsdf = (ccl_private const DiffuseBsdf *)sc;
float3 N = bsdf->N;
// distribution over the hemisphere
@@ -104,26 +106,26 @@ ccl_device int bsdf_diffuse_sample(const ShaderClosure *sc,
/* TRANSLUCENT */
-ccl_device int bsdf_translucent_setup(DiffuseBsdf *bsdf)
+ccl_device int bsdf_translucent_setup(ccl_private DiffuseBsdf *bsdf)
{
bsdf->type = CLOSURE_BSDF_TRANSLUCENT_ID;
return SD_BSDF | SD_BSDF_HAS_EVAL;
}
-ccl_device float3 bsdf_translucent_eval_reflect(const ShaderClosure *sc,
+ccl_device float3 bsdf_translucent_eval_reflect(ccl_private const ShaderClosure *sc,
const float3 I,
const float3 omega_in,
- float *pdf)
+ ccl_private float *pdf)
{
return make_float3(0.0f, 0.0f, 0.0f);
}
-ccl_device float3 bsdf_translucent_eval_transmit(const ShaderClosure *sc,
+ccl_device float3 bsdf_translucent_eval_transmit(ccl_private const ShaderClosure *sc,
const float3 I,
const float3 omega_in,
- float *pdf)
+ ccl_private float *pdf)
{
- const DiffuseBsdf *bsdf = (const DiffuseBsdf *)sc;
+ ccl_private const DiffuseBsdf *bsdf = (ccl_private const DiffuseBsdf *)sc;
float3 N = bsdf->N;
float cos_pi = fmaxf(-dot(N, omega_in), 0.0f) * M_1_PI_F;
@@ -131,20 +133,20 @@ ccl_device float3 bsdf_translucent_eval_transmit(const ShaderClosure *sc,
return make_float3(cos_pi, cos_pi, cos_pi);
}
-ccl_device int bsdf_translucent_sample(const ShaderClosure *sc,
+ccl_device int bsdf_translucent_sample(ccl_private const ShaderClosure *sc,
float3 Ng,
float3 I,
float3 dIdx,
float3 dIdy,
float randu,
float randv,
- float3 *eval,
- float3 *omega_in,
- float3 *domega_in_dx,
- float3 *domega_in_dy,
- float *pdf)
+ ccl_private float3 *eval,
+ ccl_private float3 *omega_in,
+ ccl_private float3 *domega_in_dx,
+ ccl_private float3 *domega_in_dy,
+ ccl_private float *pdf)
{
- const DiffuseBsdf *bsdf = (const DiffuseBsdf *)sc;
+ ccl_private const DiffuseBsdf *bsdf = (ccl_private const DiffuseBsdf *)sc;
float3 N = bsdf->N;
// we are viewing the surface from the right side - send a ray out with cosine
diff --git a/intern/cycles/kernel/closure/bsdf_diffuse_ramp.h b/intern/cycles/kernel/closure/bsdf_diffuse_ramp.h
index b06dd196b9e..fbb82617dad 100644
--- a/intern/cycles/kernel/closure/bsdf_diffuse_ramp.h
+++ b/intern/cycles/kernel/closure/bsdf_diffuse_ramp.h
@@ -32,14 +32,16 @@
#pragma once
+#include "kernel/sample/mapping.h"
+
CCL_NAMESPACE_BEGIN
#ifdef __OSL__
-typedef ccl_addr_space struct DiffuseRampBsdf {
+typedef struct DiffuseRampBsdf {
SHADER_CLOSURE_BASE;
- float3 *colors;
+ ccl_private float3 *colors;
} DiffuseRampBsdf;
static_assert(sizeof(ShaderClosure) >= sizeof(DiffuseRampBsdf), "DiffuseRampBsdf is too large!");
@@ -64,14 +66,14 @@ ccl_device int bsdf_diffuse_ramp_setup(DiffuseRampBsdf *bsdf)
return SD_BSDF | SD_BSDF_HAS_EVAL;
}
-ccl_device void bsdf_diffuse_ramp_blur(ShaderClosure *sc, float roughness)
+ccl_device void bsdf_diffuse_ramp_blur(ccl_private ShaderClosure *sc, float roughness)
{
}
-ccl_device float3 bsdf_diffuse_ramp_eval_reflect(const ShaderClosure *sc,
+ccl_device float3 bsdf_diffuse_ramp_eval_reflect(ccl_private const ShaderClosure *sc,
const float3 I,
const float3 omega_in,
- float *pdf)
+ ccl_private float *pdf)
{
const DiffuseRampBsdf *bsdf = (const DiffuseRampBsdf *)sc;
float3 N = bsdf->N;
@@ -81,26 +83,26 @@ ccl_device float3 bsdf_diffuse_ramp_eval_reflect(const ShaderClosure *sc,
return bsdf_diffuse_ramp_get_color(bsdf->colors, cos_pi) * M_1_PI_F;
}
-ccl_device float3 bsdf_diffuse_ramp_eval_transmit(const ShaderClosure *sc,
+ccl_device float3 bsdf_diffuse_ramp_eval_transmit(ccl_private const ShaderClosure *sc,
const float3 I,
const float3 omega_in,
- float *pdf)
+ ccl_private float *pdf)
{
return make_float3(0.0f, 0.0f, 0.0f);
}
-ccl_device int bsdf_diffuse_ramp_sample(const ShaderClosure *sc,
+ccl_device int bsdf_diffuse_ramp_sample(ccl_private const ShaderClosure *sc,
float3 Ng,
float3 I,
float3 dIdx,
float3 dIdy,
float randu,
float randv,
- float3 *eval,
- float3 *omega_in,
- float3 *domega_in_dx,
- float3 *domega_in_dy,
- float *pdf)
+ ccl_private float3 *eval,
+ ccl_private float3 *omega_in,
+ ccl_private float3 *domega_in_dx,
+ ccl_private float3 *domega_in_dy,
+ ccl_private float *pdf)
{
const DiffuseRampBsdf *bsdf = (const DiffuseRampBsdf *)sc;
float3 N = bsdf->N;
diff --git a/intern/cycles/kernel/closure/bsdf_hair.h b/intern/cycles/kernel/closure/bsdf_hair.h
index f56f78aa1f0..449a314a90e 100644
--- a/intern/cycles/kernel/closure/bsdf_hair.h
+++ b/intern/cycles/kernel/closure/bsdf_hair.h
@@ -34,7 +34,7 @@
CCL_NAMESPACE_BEGIN
-typedef ccl_addr_space struct HairBsdf {
+typedef struct HairBsdf {
SHADER_CLOSURE_BASE;
float3 T;
@@ -45,7 +45,7 @@ typedef ccl_addr_space struct HairBsdf {
static_assert(sizeof(ShaderClosure) >= sizeof(HairBsdf), "HairBsdf is too large!");
-ccl_device int bsdf_hair_reflection_setup(HairBsdf *bsdf)
+ccl_device int bsdf_hair_reflection_setup(ccl_private HairBsdf *bsdf)
{
bsdf->type = CLOSURE_BSDF_HAIR_REFLECTION_ID;
bsdf->roughness1 = clamp(bsdf->roughness1, 0.001f, 1.0f);
@@ -53,7 +53,7 @@ ccl_device int bsdf_hair_reflection_setup(HairBsdf *bsdf)
return SD_BSDF | SD_BSDF_HAS_EVAL;
}
-ccl_device int bsdf_hair_transmission_setup(HairBsdf *bsdf)
+ccl_device int bsdf_hair_transmission_setup(ccl_private HairBsdf *bsdf)
{
bsdf->type = CLOSURE_BSDF_HAIR_TRANSMISSION_ID;
bsdf->roughness1 = clamp(bsdf->roughness1, 0.001f, 1.0f);
@@ -61,12 +61,12 @@ ccl_device int bsdf_hair_transmission_setup(HairBsdf *bsdf)
return SD_BSDF | SD_BSDF_HAS_EVAL;
}
-ccl_device float3 bsdf_hair_reflection_eval_reflect(const ShaderClosure *sc,
+ccl_device float3 bsdf_hair_reflection_eval_reflect(ccl_private const ShaderClosure *sc,
const float3 I,
const float3 omega_in,
- float *pdf)
+ ccl_private float *pdf)
{
- const HairBsdf *bsdf = (const HairBsdf *)sc;
+ ccl_private const HairBsdf *bsdf = (ccl_private const HairBsdf *)sc;
float offset = bsdf->offset;
float3 Tg = bsdf->T;
float roughness1 = bsdf->roughness1;
@@ -108,28 +108,28 @@ ccl_device float3 bsdf_hair_reflection_eval_reflect(const ShaderClosure *sc,
return make_float3(*pdf, *pdf, *pdf);
}
-ccl_device float3 bsdf_hair_transmission_eval_reflect(const ShaderClosure *sc,
+ccl_device float3 bsdf_hair_transmission_eval_reflect(ccl_private const ShaderClosure *sc,
const float3 I,
const float3 omega_in,
- float *pdf)
+ ccl_private float *pdf)
{
return make_float3(0.0f, 0.0f, 0.0f);
}
-ccl_device float3 bsdf_hair_reflection_eval_transmit(const ShaderClosure *sc,
+ccl_device float3 bsdf_hair_reflection_eval_transmit(ccl_private const ShaderClosure *sc,
const float3 I,
const float3 omega_in,
- float *pdf)
+ ccl_private float *pdf)
{
return make_float3(0.0f, 0.0f, 0.0f);
}
-ccl_device float3 bsdf_hair_transmission_eval_transmit(const ShaderClosure *sc,
+ccl_device float3 bsdf_hair_transmission_eval_transmit(ccl_private const ShaderClosure *sc,
const float3 I,
const float3 omega_in,
- float *pdf)
+ ccl_private float *pdf)
{
- const HairBsdf *bsdf = (const HairBsdf *)sc;
+ ccl_private const HairBsdf *bsdf = (ccl_private const HairBsdf *)sc;
float offset = bsdf->offset;
float3 Tg = bsdf->T;
float roughness1 = bsdf->roughness1;
@@ -170,20 +170,20 @@ ccl_device float3 bsdf_hair_transmission_eval_transmit(const ShaderClosure *sc,
return make_float3(*pdf, *pdf, *pdf);
}
-ccl_device int bsdf_hair_reflection_sample(const ShaderClosure *sc,
+ccl_device int bsdf_hair_reflection_sample(ccl_private const ShaderClosure *sc,
float3 Ng,
float3 I,
float3 dIdx,
float3 dIdy,
float randu,
float randv,
- float3 *eval,
- float3 *omega_in,
- float3 *domega_in_dx,
- float3 *domega_in_dy,
- float *pdf)
+ ccl_private float3 *eval,
+ ccl_private float3 *omega_in,
+ ccl_private float3 *domega_in_dx,
+ ccl_private float3 *domega_in_dy,
+ ccl_private float *pdf)
{
- const HairBsdf *bsdf = (const HairBsdf *)sc;
+ ccl_private const HairBsdf *bsdf = (ccl_private const HairBsdf *)sc;
float offset = bsdf->offset;
float3 Tg = bsdf->T;
float roughness1 = bsdf->roughness1;
@@ -231,20 +231,20 @@ ccl_device int bsdf_hair_reflection_sample(const ShaderClosure *sc,
return LABEL_REFLECT | LABEL_GLOSSY;
}
-ccl_device int bsdf_hair_transmission_sample(const ShaderClosure *sc,
+ccl_device int bsdf_hair_transmission_sample(ccl_private const ShaderClosure *sc,
float3 Ng,
float3 I,
float3 dIdx,
float3 dIdy,
float randu,
float randv,
- float3 *eval,
- float3 *omega_in,
- float3 *domega_in_dx,
- float3 *domega_in_dy,
- float *pdf)
+ ccl_private float3 *eval,
+ ccl_private float3 *omega_in,
+ ccl_private float3 *domega_in_dx,
+ ccl_private float3 *domega_in_dy,
+ ccl_private float *pdf)
{
- const HairBsdf *bsdf = (const HairBsdf *)sc;
+ ccl_private const HairBsdf *bsdf = (ccl_private const HairBsdf *)sc;
float offset = bsdf->offset;
float3 Tg = bsdf->T;
float roughness1 = bsdf->roughness1;
diff --git a/intern/cycles/kernel/closure/bsdf_hair_principled.h b/intern/cycles/kernel/closure/bsdf_hair_principled.h
index bfe56e5ab0e..c68314889f1 100644
--- a/intern/cycles/kernel/closure/bsdf_hair_principled.h
+++ b/intern/cycles/kernel/closure/bsdf_hair_principled.h
@@ -20,16 +20,16 @@
# include <fenv.h>
#endif
-#include "kernel/kernel_color.h"
+#include "kernel/util/color.h"
CCL_NAMESPACE_BEGIN
-typedef ccl_addr_space struct PrincipledHairExtra {
+typedef struct PrincipledHairExtra {
/* Geometry data. */
float4 geom;
} PrincipledHairExtra;
-typedef ccl_addr_space struct PrincipledHairBSDF {
+typedef struct PrincipledHairBSDF {
SHADER_CLOSURE_BASE;
/* Absorption coefficient. */
@@ -46,7 +46,7 @@ typedef ccl_addr_space struct PrincipledHairBSDF {
float m0_roughness;
/* Extra closure. */
- PrincipledHairExtra *extra;
+ ccl_private PrincipledHairExtra *extra;
} PrincipledHairBSDF;
static_assert(sizeof(ShaderClosure) >= sizeof(PrincipledHairBSDF),
@@ -180,14 +180,15 @@ ccl_device_inline float longitudinal_scattering(
}
/* Combine the three values using their luminances. */
-ccl_device_inline float4 combine_with_energy(const KernelGlobals *kg, float3 c)
+ccl_device_inline float4 combine_with_energy(KernelGlobals kg, float3 c)
{
return make_float4(c.x, c.y, c.z, linear_rgb_to_gray(kg, c));
}
#ifdef __HAIR__
/* Set up the hair closure. */
-ccl_device int bsdf_principled_hair_setup(ShaderData *sd, PrincipledHairBSDF *bsdf)
+ccl_device int bsdf_principled_hair_setup(ccl_private ShaderData *sd,
+ ccl_private PrincipledHairBSDF *bsdf)
{
bsdf->type = CLOSURE_BSDF_HAIR_PRINCIPLED_ID;
bsdf->v = clamp(bsdf->v, 0.001f, 1.0f);
@@ -212,9 +213,7 @@ ccl_device int bsdf_principled_hair_setup(ShaderData *sd, PrincipledHairBSDF *bs
/* TODO: we convert this value to a cosine later and discard the sign, so
* we could probably save some operations. */
- float h = (sd->type & (PRIMITIVE_CURVE_RIBBON | PRIMITIVE_MOTION_CURVE_RIBBON)) ?
- -sd->v :
- dot(cross(sd->Ng, X), Z);
+ float h = (sd->type & PRIMITIVE_CURVE_RIBBON) ? -sd->v : dot(cross(sd->Ng, X), Z);
kernel_assert(fabsf(h) < 1.0f + 1e-4f);
kernel_assert(isfinite3_safe(Y));
@@ -228,7 +227,10 @@ ccl_device int bsdf_principled_hair_setup(ShaderData *sd, PrincipledHairBSDF *bs
#endif /* __HAIR__ */
/* Given the Fresnel term and transmittance, generate the attenuation terms for each bounce. */
-ccl_device_inline void hair_attenuation(const KernelGlobals *kg, float f, float3 T, float4 *Ap)
+ccl_device_inline void hair_attenuation(KernelGlobals kg,
+ float f,
+ float3 T,
+ ccl_private float4 *Ap)
{
/* Primary specular (R). */
Ap[0] = make_float4(f, f, f, f);
@@ -259,7 +261,7 @@ ccl_device_inline void hair_attenuation(const KernelGlobals *kg, float f, float3
ccl_device_inline void hair_alpha_angles(float sin_theta_i,
float cos_theta_i,
float alpha,
- float *angles)
+ ccl_private float *angles)
{
float sin_1alpha = sinf(alpha);
float cos_1alpha = cos_from_sin(sin_1alpha);
@@ -277,15 +279,15 @@ ccl_device_inline void hair_alpha_angles(float sin_theta_i,
}
/* Evaluation function for our shader. */
-ccl_device float3 bsdf_principled_hair_eval(const KernelGlobals *kg,
- const ShaderData *sd,
- const ShaderClosure *sc,
+ccl_device float3 bsdf_principled_hair_eval(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ ccl_private const ShaderClosure *sc,
const float3 omega_in,
- float *pdf)
+ ccl_private float *pdf)
{
kernel_assert(isfinite3_safe(sd->P) && isfinite_safe(sd->ray_length));
- const PrincipledHairBSDF *bsdf = (const PrincipledHairBSDF *)sc;
+ ccl_private const PrincipledHairBSDF *bsdf = (ccl_private const PrincipledHairBSDF *)sc;
float3 Y = float4_to_float3(bsdf->extra->geom);
float3 X = safe_normalize(sd->dPdu);
@@ -355,18 +357,18 @@ ccl_device float3 bsdf_principled_hair_eval(const KernelGlobals *kg,
}
/* Sampling function for the hair shader. */
-ccl_device int bsdf_principled_hair_sample(const KernelGlobals *kg,
- const ShaderClosure *sc,
- ShaderData *sd,
+ccl_device int bsdf_principled_hair_sample(KernelGlobals kg,
+ ccl_private const ShaderClosure *sc,
+ ccl_private ShaderData *sd,
float randu,
float randv,
- float3 *eval,
- float3 *omega_in,
- float3 *domega_in_dx,
- float3 *domega_in_dy,
- float *pdf)
+ ccl_private float3 *eval,
+ ccl_private float3 *omega_in,
+ ccl_private float3 *domega_in_dx,
+ ccl_private float3 *domega_in_dy,
+ ccl_private float *pdf)
{
- PrincipledHairBSDF *bsdf = (PrincipledHairBSDF *)sc;
+ ccl_private PrincipledHairBSDF *bsdf = (ccl_private PrincipledHairBSDF *)sc;
float3 Y = float4_to_float3(bsdf->extra->geom);
@@ -378,8 +380,8 @@ ccl_device int bsdf_principled_hair_sample(const KernelGlobals *kg,
float2 u[2];
u[0] = make_float2(randu, randv);
- u[1].x = lcg_step_float_addrspace(&sd->lcg_state);
- u[1].y = lcg_step_float_addrspace(&sd->lcg_state);
+ u[1].x = lcg_step_float(&sd->lcg_state);
+ u[1].y = lcg_step_float(&sd->lcg_state);
float sin_theta_o = wo.x;
float cos_theta_o = cos_from_sin(sin_theta_o);
@@ -482,9 +484,9 @@ ccl_device int bsdf_principled_hair_sample(const KernelGlobals *kg,
}
/* Implements Filter Glossy by capping the effective roughness. */
-ccl_device void bsdf_principled_hair_blur(ShaderClosure *sc, float roughness)
+ccl_device void bsdf_principled_hair_blur(ccl_private ShaderClosure *sc, float roughness)
{
- PrincipledHairBSDF *bsdf = (PrincipledHairBSDF *)sc;
+ ccl_private PrincipledHairBSDF *bsdf = (ccl_private PrincipledHairBSDF *)sc;
bsdf->v = fmaxf(roughness, bsdf->v);
bsdf->s = fmaxf(roughness, bsdf->s);
@@ -500,9 +502,9 @@ ccl_device_inline float bsdf_principled_hair_albedo_roughness_scale(
return (((((0.245f * x) + 5.574f) * x - 10.73f) * x + 2.532f) * x - 0.215f) * x + 5.969f;
}
-ccl_device float3 bsdf_principled_hair_albedo(const ShaderClosure *sc)
+ccl_device float3 bsdf_principled_hair_albedo(ccl_private const ShaderClosure *sc)
{
- PrincipledHairBSDF *bsdf = (PrincipledHairBSDF *)sc;
+ ccl_private PrincipledHairBSDF *bsdf = (ccl_private PrincipledHairBSDF *)sc;
return exp3(-sqrt(bsdf->sigma) * bsdf_principled_hair_albedo_roughness_scale(bsdf->v));
}
diff --git a/intern/cycles/kernel/closure/bsdf_microfacet.h b/intern/cycles/kernel/closure/bsdf_microfacet.h
index 227cb448b47..466ba3e229e 100644
--- a/intern/cycles/kernel/closure/bsdf_microfacet.h
+++ b/intern/cycles/kernel/closure/bsdf_microfacet.h
@@ -32,22 +32,25 @@
#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
-typedef ccl_addr_space struct MicrofacetExtra {
+typedef struct MicrofacetExtra {
float3 color, cspec0;
float3 fresnel_color;
float clearcoat;
} MicrofacetExtra;
-typedef ccl_addr_space struct MicrofacetBsdf {
+typedef struct MicrofacetBsdf {
SHADER_CLOSURE_BASE;
float alpha_x, alpha_y, ior;
- MicrofacetExtra *extra;
+ ccl_private MicrofacetExtra *extra;
float3 T;
} MicrofacetBsdf;
@@ -55,14 +58,14 @@ static_assert(sizeof(ShaderClosure) >= sizeof(MicrofacetBsdf), "MicrofacetBsdf i
/* Beckmann and GGX microfacet importance sampling. */
-ccl_device_inline void microfacet_beckmann_sample_slopes(const KernelGlobals *kg,
+ccl_device_inline void microfacet_beckmann_sample_slopes(KernelGlobals kg,
const float cos_theta_i,
const float sin_theta_i,
float randu,
float randv,
- float *slope_x,
- float *slope_y,
- float *G1i)
+ ccl_private float *slope_x,
+ ccl_private float *slope_y,
+ ccl_private float *G1i)
{
/* special case (normal incidence) */
if (cos_theta_i >= 0.99999f) {
@@ -146,9 +149,9 @@ ccl_device_inline void microfacet_ggx_sample_slopes(const float cos_theta_i,
const float sin_theta_i,
float randu,
float randv,
- float *slope_x,
- float *slope_y,
- float *G1i)
+ ccl_private float *slope_x,
+ ccl_private float *slope_y,
+ ccl_private float *G1i)
{
/* special case (normal incidence) */
if (cos_theta_i >= 0.99999f) {
@@ -195,14 +198,14 @@ ccl_device_inline void microfacet_ggx_sample_slopes(const float cos_theta_i,
*slope_y = S * z * safe_sqrtf(1.0f + (*slope_x) * (*slope_x));
}
-ccl_device_forceinline float3 microfacet_sample_stretched(const KernelGlobals *kg,
+ccl_device_forceinline float3 microfacet_sample_stretched(KernelGlobals kg,
const float3 omega_i,
const float alpha_x,
const float alpha_y,
const float randu,
const float randv,
bool beckmann,
- float *G1i)
+ ccl_private float *G1i)
{
/* 1. stretch omega_i */
float3 omega_i_ = make_float3(alpha_x * omega_i.x, alpha_y * omega_i.y, omega_i.z);
@@ -254,7 +257,9 @@ ccl_device_forceinline float3 microfacet_sample_stretched(const KernelGlobals *k
*
* Else it is simply white
*/
-ccl_device_forceinline float3 reflection_color(const MicrofacetBsdf *bsdf, float3 L, float3 H)
+ccl_device_forceinline float3 reflection_color(ccl_private const MicrofacetBsdf *bsdf,
+ float3 L,
+ float3 H)
{
float3 F = make_float3(1.0f, 1.0f, 1.0f);
bool use_fresnel = (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID ||
@@ -277,8 +282,8 @@ ccl_device_forceinline float D_GTR1(float NdotH, float alpha)
return (alpha2 - 1.0f) / (M_PI_F * logf(alpha2) * t);
}
-ccl_device_forceinline void bsdf_microfacet_fresnel_color(const ShaderData *sd,
- MicrofacetBsdf *bsdf)
+ccl_device_forceinline void bsdf_microfacet_fresnel_color(ccl_private const ShaderData *sd,
+ ccl_private MicrofacetBsdf *bsdf)
{
kernel_assert(CLOSURE_IS_BSDF_MICROFACET_FRESNEL(bsdf->type));
@@ -306,12 +311,12 @@ ccl_device_forceinline void bsdf_microfacet_fresnel_color(const ShaderData *sd,
* Anisotropy is only supported for reflection currently, but adding it for
* transmission is just a matter of copying code from reflection if needed. */
-ccl_device int bsdf_microfacet_ggx_setup(MicrofacetBsdf *bsdf)
+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;
@@ -319,19 +324,20 @@ ccl_device int bsdf_microfacet_ggx_setup(MicrofacetBsdf *bsdf)
}
/* Required to maintain OSL interface. */
-ccl_device int bsdf_microfacet_ggx_isotropic_setup(MicrofacetBsdf *bsdf)
+ccl_device int bsdf_microfacet_ggx_isotropic_setup(ccl_private MicrofacetBsdf *bsdf)
{
bsdf->alpha_y = bsdf->alpha_x;
return bsdf_microfacet_ggx_setup(bsdf);
}
-ccl_device int bsdf_microfacet_ggx_fresnel_setup(MicrofacetBsdf *bsdf, const ShaderData *sd)
+ccl_device int bsdf_microfacet_ggx_fresnel_setup(ccl_private MicrofacetBsdf *bsdf,
+ ccl_private const ShaderData *sd)
{
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;
@@ -340,11 +346,12 @@ ccl_device int bsdf_microfacet_ggx_fresnel_setup(MicrofacetBsdf *bsdf, const Sha
return SD_BSDF | SD_BSDF_HAS_EVAL;
}
-ccl_device int bsdf_microfacet_ggx_clearcoat_setup(MicrofacetBsdf *bsdf, const ShaderData *sd)
+ccl_device int bsdf_microfacet_ggx_clearcoat_setup(ccl_private MicrofacetBsdf *bsdf,
+ ccl_private const ShaderData *sd)
{
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;
@@ -354,11 +361,11 @@ ccl_device int bsdf_microfacet_ggx_clearcoat_setup(MicrofacetBsdf *bsdf, const S
return SD_BSDF | SD_BSDF_HAS_EVAL;
}
-ccl_device int bsdf_microfacet_ggx_refraction_setup(MicrofacetBsdf *bsdf)
+ccl_device int bsdf_microfacet_ggx_refraction_setup(ccl_private MicrofacetBsdf *bsdf)
{
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;
@@ -366,20 +373,20 @@ ccl_device int bsdf_microfacet_ggx_refraction_setup(MicrofacetBsdf *bsdf)
return SD_BSDF | SD_BSDF_HAS_EVAL;
}
-ccl_device void bsdf_microfacet_ggx_blur(ShaderClosure *sc, float roughness)
+ccl_device void bsdf_microfacet_ggx_blur(ccl_private ShaderClosure *sc, float roughness)
{
- MicrofacetBsdf *bsdf = (MicrofacetBsdf *)sc;
+ ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)sc;
bsdf->alpha_x = fmaxf(roughness, bsdf->alpha_x);
bsdf->alpha_y = fmaxf(roughness, bsdf->alpha_y);
}
-ccl_device float3 bsdf_microfacet_ggx_eval_reflect(const ShaderClosure *sc,
+ccl_device float3 bsdf_microfacet_ggx_eval_reflect(ccl_private const ShaderClosure *sc,
const float3 I,
const float3 omega_in,
- float *pdf)
+ ccl_private float *pdf)
{
- const MicrofacetBsdf *bsdf = (const MicrofacetBsdf *)sc;
+ ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc;
float alpha_x = bsdf->alpha_x;
float alpha_y = bsdf->alpha_y;
bool m_refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
@@ -487,12 +494,12 @@ ccl_device float3 bsdf_microfacet_ggx_eval_reflect(const ShaderClosure *sc,
return make_float3(0.0f, 0.0f, 0.0f);
}
-ccl_device float3 bsdf_microfacet_ggx_eval_transmit(const ShaderClosure *sc,
+ccl_device float3 bsdf_microfacet_ggx_eval_transmit(ccl_private const ShaderClosure *sc,
const float3 I,
const float3 omega_in,
- float *pdf)
+ ccl_private float *pdf)
{
- const MicrofacetBsdf *bsdf = (const MicrofacetBsdf *)sc;
+ ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc;
float alpha_x = bsdf->alpha_x;
float alpha_y = bsdf->alpha_y;
float m_eta = bsdf->ior;
@@ -545,21 +552,21 @@ ccl_device float3 bsdf_microfacet_ggx_eval_transmit(const ShaderClosure *sc,
return make_float3(out, out, out);
}
-ccl_device int bsdf_microfacet_ggx_sample(const KernelGlobals *kg,
- const ShaderClosure *sc,
+ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals kg,
+ ccl_private const ShaderClosure *sc,
float3 Ng,
float3 I,
float3 dIdx,
float3 dIdy,
float randu,
float randv,
- float3 *eval,
- float3 *omega_in,
- float3 *domega_in_dx,
- float3 *domega_in_dy,
- float *pdf)
+ ccl_private float3 *eval,
+ ccl_private float3 *omega_in,
+ ccl_private float3 *domega_in_dx,
+ ccl_private float3 *domega_in_dy,
+ ccl_private float *pdf)
{
- const MicrofacetBsdf *bsdf = (const MicrofacetBsdf *)sc;
+ ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc;
float alpha_x = bsdf->alpha_x;
float alpha_y = bsdf->alpha_y;
bool m_refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
@@ -774,35 +781,35 @@ ccl_device int bsdf_microfacet_ggx_sample(const KernelGlobals *kg,
* Microfacet Models for Refraction through Rough Surfaces
* B. Walter, S. R. Marschner, H. Li, K. E. Torrance, EGSR 2007 */
-ccl_device int bsdf_microfacet_beckmann_setup(MicrofacetBsdf *bsdf)
+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;
}
/* Required to maintain OSL interface. */
-ccl_device int bsdf_microfacet_beckmann_isotropic_setup(MicrofacetBsdf *bsdf)
+ccl_device int bsdf_microfacet_beckmann_isotropic_setup(ccl_private MicrofacetBsdf *bsdf)
{
bsdf->alpha_y = bsdf->alpha_x;
return bsdf_microfacet_beckmann_setup(bsdf);
}
-ccl_device int bsdf_microfacet_beckmann_refraction_setup(MicrofacetBsdf *bsdf)
+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;
return SD_BSDF | SD_BSDF_HAS_EVAL;
}
-ccl_device void bsdf_microfacet_beckmann_blur(ShaderClosure *sc, float roughness)
+ccl_device void bsdf_microfacet_beckmann_blur(ccl_private ShaderClosure *sc, float roughness)
{
- MicrofacetBsdf *bsdf = (MicrofacetBsdf *)sc;
+ ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)sc;
bsdf->alpha_x = fmaxf(roughness, bsdf->alpha_x);
bsdf->alpha_y = fmaxf(roughness, bsdf->alpha_y);
@@ -839,12 +846,12 @@ ccl_device_inline float bsdf_beckmann_aniso_G1(
return ((2.181f * a + 3.535f) * a) / ((2.577f * a + 2.276f) * a + 1.0f);
}
-ccl_device float3 bsdf_microfacet_beckmann_eval_reflect(const ShaderClosure *sc,
+ccl_device float3 bsdf_microfacet_beckmann_eval_reflect(ccl_private const ShaderClosure *sc,
const float3 I,
const float3 omega_in,
- float *pdf)
+ ccl_private float *pdf)
{
- const MicrofacetBsdf *bsdf = (const MicrofacetBsdf *)sc;
+ ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc;
float alpha_x = bsdf->alpha_x;
float alpha_y = bsdf->alpha_y;
bool m_refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID;
@@ -918,12 +925,12 @@ ccl_device float3 bsdf_microfacet_beckmann_eval_reflect(const ShaderClosure *sc,
return make_float3(0.0f, 0.0f, 0.0f);
}
-ccl_device float3 bsdf_microfacet_beckmann_eval_transmit(const ShaderClosure *sc,
+ccl_device float3 bsdf_microfacet_beckmann_eval_transmit(ccl_private const ShaderClosure *sc,
const float3 I,
const float3 omega_in,
- float *pdf)
+ ccl_private float *pdf)
{
- const MicrofacetBsdf *bsdf = (const MicrofacetBsdf *)sc;
+ ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc;
float alpha_x = bsdf->alpha_x;
float alpha_y = bsdf->alpha_y;
float m_eta = bsdf->ior;
@@ -973,21 +980,21 @@ ccl_device float3 bsdf_microfacet_beckmann_eval_transmit(const ShaderClosure *sc
return make_float3(out, out, out);
}
-ccl_device int bsdf_microfacet_beckmann_sample(const KernelGlobals *kg,
- const ShaderClosure *sc,
+ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals kg,
+ ccl_private const ShaderClosure *sc,
float3 Ng,
float3 I,
float3 dIdx,
float3 dIdy,
float randu,
float randv,
- float3 *eval,
- float3 *omega_in,
- float3 *domega_in_dx,
- float3 *domega_in_dy,
- float *pdf)
+ ccl_private float3 *eval,
+ ccl_private float3 *omega_in,
+ ccl_private float3 *domega_in_dx,
+ ccl_private float3 *domega_in_dy,
+ ccl_private float *pdf)
{
- const MicrofacetBsdf *bsdf = (const MicrofacetBsdf *)sc;
+ ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc;
float alpha_x = bsdf->alpha_x;
float alpha_y = bsdf->alpha_y;
bool m_refractive = 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 68d5071dbce..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
@@ -105,7 +108,7 @@ ccl_device_forceinline float3 mf_sample_vndf(const float3 wi,
/* Phase function for reflective materials. */
ccl_device_forceinline float3 mf_sample_phase_glossy(const float3 wi,
- float3 *weight,
+ ccl_private float3 *weight,
const float3 wm)
{
return -wi + 2.0f * wm * dot(wi, wm);
@@ -140,8 +143,11 @@ ccl_device_forceinline float3 mf_eval_phase_glossy(const float3 w,
/* Phase function for dielectric transmissive materials, including both reflection and refraction
* according to the dielectric fresnel term. */
-ccl_device_forceinline float3 mf_sample_phase_glass(
- const float3 wi, const float eta, const float3 wm, const float randV, bool *outside)
+ccl_device_forceinline float3 mf_sample_phase_glass(const float3 wi,
+ const float eta,
+ const float3 wm,
+ const float randV,
+ ccl_private bool *outside)
{
float cosI = dot(wi, wm);
float f = fresnel_dielectric_cos(cosI, eta);
@@ -214,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). */
@@ -234,8 +240,12 @@ ccl_device_forceinline float mf_G1(const float3 w, const float C1, const float l
/* Sampling from the visible height distribution (based on page 17 of the supplemental
* implementation). */
-ccl_device_forceinline bool mf_sample_height(
- const float3 w, float *h, float *C1, float *G1, float *lambda, const float U)
+ccl_device_forceinline bool mf_sample_height(const float3 w,
+ ccl_private float *h,
+ ccl_private float *C1,
+ ccl_private float *G1,
+ ccl_private float *lambda,
+ const float U)
{
if (w.z > 0.9999f)
return false;
@@ -274,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)
@@ -282,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;
@@ -292,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)
@@ -364,9 +374,9 @@ ccl_device_forceinline float mf_glass_pdf(const float3 wi,
#define MF_MULTI_GLOSSY
#include "kernel/closure/bsdf_microfacet_multi_impl.h"
-ccl_device void bsdf_microfacet_multi_ggx_blur(ShaderClosure *sc, float roughness)
+ccl_device void bsdf_microfacet_multi_ggx_blur(ccl_private ShaderClosure *sc, float roughness)
{
- MicrofacetBsdf *bsdf = (MicrofacetBsdf *)sc;
+ ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)sc;
bsdf->alpha_x = fmaxf(roughness, bsdf->alpha_x);
bsdf->alpha_y = fmaxf(roughness, bsdf->alpha_y);
@@ -376,7 +386,7 @@ ccl_device void bsdf_microfacet_multi_ggx_blur(ShaderClosure *sc, float roughnes
/* Multiscattering GGX Glossy closure */
-ccl_device int bsdf_microfacet_multi_ggx_common_setup(MicrofacetBsdf *bsdf)
+ccl_device int bsdf_microfacet_multi_ggx_common_setup(ccl_private MicrofacetBsdf *bsdf)
{
bsdf->alpha_x = clamp(bsdf->alpha_x, 1e-4f, 1.0f);
bsdf->alpha_y = clamp(bsdf->alpha_y, 1e-4f, 1.0f);
@@ -386,7 +396,7 @@ ccl_device int bsdf_microfacet_multi_ggx_common_setup(MicrofacetBsdf *bsdf)
return SD_BSDF | SD_BSDF_HAS_EVAL | SD_BSDF_NEEDS_LCG;
}
-ccl_device int bsdf_microfacet_multi_ggx_setup(MicrofacetBsdf *bsdf)
+ccl_device int bsdf_microfacet_multi_ggx_setup(ccl_private MicrofacetBsdf *bsdf)
{
if (is_zero(bsdf->T))
bsdf->T = make_float3(1.0f, 0.0f, 0.0f);
@@ -396,7 +406,8 @@ ccl_device int bsdf_microfacet_multi_ggx_setup(MicrofacetBsdf *bsdf)
return bsdf_microfacet_multi_ggx_common_setup(bsdf);
}
-ccl_device int bsdf_microfacet_multi_ggx_fresnel_setup(MicrofacetBsdf *bsdf, const ShaderData *sd)
+ccl_device int bsdf_microfacet_multi_ggx_fresnel_setup(ccl_private MicrofacetBsdf *bsdf,
+ ccl_private const ShaderData *sd)
{
if (is_zero(bsdf->T))
bsdf->T = make_float3(1.0f, 0.0f, 0.0f);
@@ -408,7 +419,7 @@ ccl_device int bsdf_microfacet_multi_ggx_fresnel_setup(MicrofacetBsdf *bsdf, con
return bsdf_microfacet_multi_ggx_common_setup(bsdf);
}
-ccl_device int bsdf_microfacet_multi_ggx_refraction_setup(MicrofacetBsdf *bsdf)
+ccl_device int bsdf_microfacet_multi_ggx_refraction_setup(ccl_private MicrofacetBsdf *bsdf)
{
bsdf->alpha_y = bsdf->alpha_x;
@@ -417,23 +428,23 @@ ccl_device int bsdf_microfacet_multi_ggx_refraction_setup(MicrofacetBsdf *bsdf)
return bsdf_microfacet_multi_ggx_common_setup(bsdf);
}
-ccl_device float3 bsdf_microfacet_multi_ggx_eval_transmit(const ShaderClosure *sc,
+ccl_device float3 bsdf_microfacet_multi_ggx_eval_transmit(ccl_private const ShaderClosure *sc,
const float3 I,
const float3 omega_in,
- float *pdf,
- ccl_addr_space uint *lcg_state)
+ ccl_private float *pdf,
+ ccl_private uint *lcg_state)
{
*pdf = 0.0f;
return make_float3(0.0f, 0.0f, 0.0f);
}
-ccl_device float3 bsdf_microfacet_multi_ggx_eval_reflect(const ShaderClosure *sc,
+ccl_device float3 bsdf_microfacet_multi_ggx_eval_reflect(ccl_private const ShaderClosure *sc,
const float3 I,
const float3 omega_in,
- float *pdf,
- ccl_addr_space uint *lcg_state)
+ ccl_private float *pdf,
+ ccl_private uint *lcg_state)
{
- const MicrofacetBsdf *bsdf = (const MicrofacetBsdf *)sc;
+ ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc;
if (bsdf->alpha_x * bsdf->alpha_y < 1e-7f) {
return make_float3(0.0f, 0.0f, 0.0f);
@@ -468,22 +479,22 @@ ccl_device float3 bsdf_microfacet_multi_ggx_eval_reflect(const ShaderClosure *sc
bsdf->extra->cspec0);
}
-ccl_device int bsdf_microfacet_multi_ggx_sample(const KernelGlobals *kg,
- const ShaderClosure *sc,
+ccl_device int bsdf_microfacet_multi_ggx_sample(KernelGlobals kg,
+ ccl_private const ShaderClosure *sc,
float3 Ng,
float3 I,
float3 dIdx,
float3 dIdy,
float randu,
float randv,
- float3 *eval,
- float3 *omega_in,
- float3 *domega_in_dx,
- float3 *domega_in_dy,
- float *pdf,
- ccl_addr_space uint *lcg_state)
+ ccl_private float3 *eval,
+ ccl_private float3 *omega_in,
+ ccl_private float3 *domega_in_dx,
+ ccl_private float3 *domega_in_dy,
+ ccl_private float *pdf,
+ ccl_private uint *lcg_state)
{
- const MicrofacetBsdf *bsdf = (const MicrofacetBsdf *)sc;
+ ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc;
float3 X, Y, Z;
Z = bsdf->N;
@@ -536,7 +547,7 @@ ccl_device int bsdf_microfacet_multi_ggx_sample(const KernelGlobals *kg,
/* Multiscattering GGX Glass closure */
-ccl_device int bsdf_microfacet_multi_ggx_glass_setup(MicrofacetBsdf *bsdf)
+ccl_device int bsdf_microfacet_multi_ggx_glass_setup(ccl_private MicrofacetBsdf *bsdf)
{
bsdf->alpha_x = clamp(bsdf->alpha_x, 1e-4f, 1.0f);
bsdf->alpha_y = bsdf->alpha_x;
@@ -548,8 +559,8 @@ ccl_device int bsdf_microfacet_multi_ggx_glass_setup(MicrofacetBsdf *bsdf)
return SD_BSDF | SD_BSDF_HAS_EVAL | SD_BSDF_NEEDS_LCG;
}
-ccl_device int bsdf_microfacet_multi_ggx_glass_fresnel_setup(MicrofacetBsdf *bsdf,
- const ShaderData *sd)
+ccl_device int bsdf_microfacet_multi_ggx_glass_fresnel_setup(ccl_private MicrofacetBsdf *bsdf,
+ ccl_private const ShaderData *sd)
{
bsdf->alpha_x = clamp(bsdf->alpha_x, 1e-4f, 1.0f);
bsdf->alpha_y = bsdf->alpha_x;
@@ -564,13 +575,14 @@ ccl_device int bsdf_microfacet_multi_ggx_glass_fresnel_setup(MicrofacetBsdf *bsd
return SD_BSDF | SD_BSDF_HAS_EVAL | SD_BSDF_NEEDS_LCG;
}
-ccl_device float3 bsdf_microfacet_multi_ggx_glass_eval_transmit(const ShaderClosure *sc,
- const float3 I,
- const float3 omega_in,
- float *pdf,
- ccl_addr_space uint *lcg_state)
+ccl_device float3
+bsdf_microfacet_multi_ggx_glass_eval_transmit(ccl_private const ShaderClosure *sc,
+ const float3 I,
+ const float3 omega_in,
+ ccl_private float *pdf,
+ ccl_private uint *lcg_state)
{
- const MicrofacetBsdf *bsdf = (const MicrofacetBsdf *)sc;
+ ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc;
if (bsdf->alpha_x * bsdf->alpha_y < 1e-7f) {
return make_float3(0.0f, 0.0f, 0.0f);
@@ -596,13 +608,13 @@ ccl_device float3 bsdf_microfacet_multi_ggx_glass_eval_transmit(const ShaderClos
bsdf->extra->color);
}
-ccl_device float3 bsdf_microfacet_multi_ggx_glass_eval_reflect(const ShaderClosure *sc,
+ccl_device float3 bsdf_microfacet_multi_ggx_glass_eval_reflect(ccl_private const ShaderClosure *sc,
const float3 I,
const float3 omega_in,
- float *pdf,
- ccl_addr_space uint *lcg_state)
+ ccl_private float *pdf,
+ ccl_private uint *lcg_state)
{
- const MicrofacetBsdf *bsdf = (const MicrofacetBsdf *)sc;
+ ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc;
if (bsdf->alpha_x * bsdf->alpha_y < 1e-7f) {
return make_float3(0.0f, 0.0f, 0.0f);
@@ -630,22 +642,22 @@ ccl_device float3 bsdf_microfacet_multi_ggx_glass_eval_reflect(const ShaderClosu
bsdf->extra->cspec0);
}
-ccl_device int bsdf_microfacet_multi_ggx_glass_sample(const KernelGlobals *kg,
- const ShaderClosure *sc,
+ccl_device int bsdf_microfacet_multi_ggx_glass_sample(KernelGlobals kg,
+ ccl_private const ShaderClosure *sc,
float3 Ng,
float3 I,
float3 dIdx,
float3 dIdy,
float randu,
float randv,
- float3 *eval,
- float3 *omega_in,
- float3 *domega_in_dx,
- float3 *domega_in_dy,
- float *pdf,
- ccl_addr_space uint *lcg_state)
+ ccl_private float3 *eval,
+ ccl_private float3 *omega_in,
+ ccl_private float3 *domega_in_dx,
+ ccl_private float3 *domega_in_dy,
+ ccl_private float *pdf,
+ ccl_private uint *lcg_state)
{
- const MicrofacetBsdf *bsdf = (const MicrofacetBsdf *)sc;
+ ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc;
float3 X, Y, Z;
Z = bsdf->N;
diff --git a/intern/cycles/kernel/closure/bsdf_microfacet_multi_impl.h b/intern/cycles/kernel/closure/bsdf_microfacet_multi_impl.h
index 04d9b22d7d2..d23cc16cff3 100644
--- a/intern/cycles/kernel/closure/bsdf_microfacet_multi_impl.h
+++ b/intern/cycles/kernel/closure/bsdf_microfacet_multi_impl.h
@@ -31,7 +31,7 @@ ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_eval)(float3 wi,
const float3 color,
const float alpha_x,
const float alpha_y,
- ccl_addr_space uint *lcg_state,
+ ccl_private uint *lcg_state,
const float eta,
bool use_fresnel,
const float3 cspec0)
@@ -101,12 +101,12 @@ ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_eval)(float3 wi,
for (int order = 0; order < 10; order++) {
/* Sample microfacet height. */
- float height_rand = lcg_step_float_addrspace(lcg_state);
+ float height_rand = lcg_step_float(lcg_state);
if (!mf_sample_height(wr, &hr, &C1_r, &G1_r, &lambda_r, height_rand))
break;
/* Sample microfacet normal. */
- float vndf_rand_y = lcg_step_float_addrspace(lcg_state);
- float vndf_rand_x = lcg_step_float_addrspace(lcg_state);
+ float vndf_rand_y = lcg_step_float(lcg_state);
+ float vndf_rand_x = lcg_step_float(lcg_state);
float3 wm = mf_sample_vndf(-wr, alpha, vndf_rand_x, vndf_rand_y);
#ifdef MF_MULTI_GLASS
@@ -145,7 +145,7 @@ ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_eval)(float3 wi,
#ifdef MF_MULTI_GLASS
bool next_outside;
float3 wi_prev = -wr;
- float phase_rand = lcg_step_float_addrspace(lcg_state);
+ float phase_rand = lcg_step_float(lcg_state);
wr = mf_sample_phase_glass(-wr, outside ? eta : 1.0f / eta, wm, phase_rand, &next_outside);
if (!next_outside) {
outside = !outside;
@@ -186,11 +186,11 @@ ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_eval)(float3 wi,
* reflection losses due to coloring or fresnel absorption in conductors, the sampling is optimal.
*/
ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_sample)(float3 wi,
- float3 *wo,
+ ccl_private float3 *wo,
const float3 color,
const float alpha_x,
const float alpha_y,
- ccl_addr_space uint *lcg_state,
+ ccl_private uint *lcg_state,
const float eta,
bool use_fresnel,
const float3 cspec0)
@@ -213,15 +213,15 @@ ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_sample)(float3 wi,
int order;
for (order = 0; order < 10; order++) {
/* Sample microfacet height. */
- float height_rand = lcg_step_float_addrspace(lcg_state);
+ float height_rand = lcg_step_float(lcg_state);
if (!mf_sample_height(wr, &hr, &C1_r, &G1_r, &lambda_r, height_rand)) {
/* The random walk has left the surface. */
*wo = outside ? wr : -wr;
return throughput;
}
/* Sample microfacet normal. */
- float vndf_rand_y = lcg_step_float_addrspace(lcg_state);
- float vndf_rand_x = lcg_step_float_addrspace(lcg_state);
+ float vndf_rand_y = lcg_step_float(lcg_state);
+ float vndf_rand_x = lcg_step_float(lcg_state);
float3 wm = mf_sample_vndf(-wr, alpha, vndf_rand_x, vndf_rand_y);
/* First-bounce color is already accounted for in mix weight. */
@@ -232,7 +232,7 @@ ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_sample)(float3 wi,
#ifdef MF_MULTI_GLASS
bool next_outside;
float3 wi_prev = -wr;
- float phase_rand = lcg_step_float_addrspace(lcg_state);
+ float phase_rand = lcg_step_float(lcg_state);
wr = mf_sample_phase_glass(-wr, outside ? eta : 1.0f / eta, wm, phase_rand, &next_outside);
if (!next_outside) {
hr = -hr;
diff --git a/intern/cycles/kernel/closure/bsdf_oren_nayar.h b/intern/cycles/kernel/closure/bsdf_oren_nayar.h
index be12d47f0ea..8827309a811 100644
--- a/intern/cycles/kernel/closure/bsdf_oren_nayar.h
+++ b/intern/cycles/kernel/closure/bsdf_oren_nayar.h
@@ -18,7 +18,7 @@
CCL_NAMESPACE_BEGIN
-typedef ccl_addr_space struct OrenNayarBsdf {
+typedef struct OrenNayarBsdf {
SHADER_CLOSURE_BASE;
float roughness;
@@ -28,12 +28,12 @@ typedef ccl_addr_space struct OrenNayarBsdf {
static_assert(sizeof(ShaderClosure) >= sizeof(OrenNayarBsdf), "OrenNayarBsdf is too large!");
-ccl_device float3 bsdf_oren_nayar_get_intensity(const ShaderClosure *sc,
+ccl_device float3 bsdf_oren_nayar_get_intensity(ccl_private const ShaderClosure *sc,
float3 n,
float3 v,
float3 l)
{
- const OrenNayarBsdf *bsdf = (const OrenNayarBsdf *)sc;
+ ccl_private const OrenNayarBsdf *bsdf = (ccl_private const OrenNayarBsdf *)sc;
float nl = max(dot(n, l), 0.0f);
float nv = max(dot(n, v), 0.0f);
float t = dot(l, v) - nl * nv;
@@ -44,13 +44,13 @@ ccl_device float3 bsdf_oren_nayar_get_intensity(const ShaderClosure *sc,
return make_float3(is, is, is);
}
-ccl_device int bsdf_oren_nayar_setup(OrenNayarBsdf *bsdf)
+ccl_device int bsdf_oren_nayar_setup(ccl_private OrenNayarBsdf *bsdf)
{
float sigma = bsdf->roughness;
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);
@@ -60,12 +60,12 @@ ccl_device int bsdf_oren_nayar_setup(OrenNayarBsdf *bsdf)
return SD_BSDF | SD_BSDF_HAS_EVAL;
}
-ccl_device float3 bsdf_oren_nayar_eval_reflect(const ShaderClosure *sc,
+ccl_device float3 bsdf_oren_nayar_eval_reflect(ccl_private const ShaderClosure *sc,
const float3 I,
const float3 omega_in,
- float *pdf)
+ ccl_private float *pdf)
{
- const OrenNayarBsdf *bsdf = (const OrenNayarBsdf *)sc;
+ ccl_private const OrenNayarBsdf *bsdf = (ccl_private const OrenNayarBsdf *)sc;
if (dot(bsdf->N, omega_in) > 0.0f) {
*pdf = 0.5f * M_1_PI_F;
return bsdf_oren_nayar_get_intensity(sc, bsdf->N, I, omega_in);
@@ -76,28 +76,28 @@ ccl_device float3 bsdf_oren_nayar_eval_reflect(const ShaderClosure *sc,
}
}
-ccl_device float3 bsdf_oren_nayar_eval_transmit(const ShaderClosure *sc,
+ccl_device float3 bsdf_oren_nayar_eval_transmit(ccl_private const ShaderClosure *sc,
const float3 I,
const float3 omega_in,
- float *pdf)
+ ccl_private float *pdf)
{
return make_float3(0.0f, 0.0f, 0.0f);
}
-ccl_device int bsdf_oren_nayar_sample(const ShaderClosure *sc,
+ccl_device int bsdf_oren_nayar_sample(ccl_private const ShaderClosure *sc,
float3 Ng,
float3 I,
float3 dIdx,
float3 dIdy,
float randu,
float randv,
- float3 *eval,
- float3 *omega_in,
- float3 *domega_in_dx,
- float3 *domega_in_dy,
- float *pdf)
+ ccl_private float3 *eval,
+ ccl_private float3 *omega_in,
+ ccl_private float3 *domega_in_dx,
+ ccl_private float3 *domega_in_dy,
+ ccl_private float *pdf)
{
- const OrenNayarBsdf *bsdf = (const OrenNayarBsdf *)sc;
+ ccl_private const OrenNayarBsdf *bsdf = (ccl_private const OrenNayarBsdf *)sc;
sample_uniform_hemisphere(bsdf->N, randu, randv, omega_in, pdf);
if (dot(Ng, *omega_in) > 0.0f) {
diff --git a/intern/cycles/kernel/closure/bsdf_phong_ramp.h b/intern/cycles/kernel/closure/bsdf_phong_ramp.h
index 43f8cf71c59..74cc62d917b 100644
--- a/intern/cycles/kernel/closure/bsdf_phong_ramp.h
+++ b/intern/cycles/kernel/closure/bsdf_phong_ramp.h
@@ -36,11 +36,11 @@ CCL_NAMESPACE_BEGIN
#ifdef __OSL__
-typedef ccl_addr_space struct PhongRampBsdf {
+typedef struct PhongRampBsdf {
SHADER_CLOSURE_BASE;
float exponent;
- float3 *colors;
+ ccl_private float3 *colors;
} PhongRampBsdf;
static_assert(sizeof(ShaderClosure) >= sizeof(PhongRampBsdf), "PhongRampBsdf is too large!");
@@ -59,19 +59,19 @@ ccl_device float3 bsdf_phong_ramp_get_color(const float3 colors[8], float pos)
return colors[ipos] * (1.0f - offset) + colors[ipos + 1] * offset;
}
-ccl_device int bsdf_phong_ramp_setup(PhongRampBsdf *bsdf)
+ccl_device int bsdf_phong_ramp_setup(ccl_private PhongRampBsdf *bsdf)
{
bsdf->type = CLOSURE_BSDF_PHONG_RAMP_ID;
bsdf->exponent = max(bsdf->exponent, 0.0f);
return SD_BSDF | SD_BSDF_HAS_EVAL;
}
-ccl_device float3 bsdf_phong_ramp_eval_reflect(const ShaderClosure *sc,
+ccl_device float3 bsdf_phong_ramp_eval_reflect(ccl_private const ShaderClosure *sc,
const float3 I,
const float3 omega_in,
- float *pdf)
+ ccl_private float *pdf)
{
- const PhongRampBsdf *bsdf = (const PhongRampBsdf *)sc;
+ ccl_private const PhongRampBsdf *bsdf = (ccl_private const PhongRampBsdf *)sc;
float m_exponent = bsdf->exponent;
float cosNI = dot(bsdf->N, omega_in);
float cosNO = dot(bsdf->N, I);
@@ -92,28 +92,28 @@ ccl_device float3 bsdf_phong_ramp_eval_reflect(const ShaderClosure *sc,
return make_float3(0.0f, 0.0f, 0.0f);
}
-ccl_device float3 bsdf_phong_ramp_eval_transmit(const ShaderClosure *sc,
+ccl_device float3 bsdf_phong_ramp_eval_transmit(ccl_private const ShaderClosure *sc,
const float3 I,
const float3 omega_in,
- float *pdf)
+ ccl_private float *pdf)
{
return make_float3(0.0f, 0.0f, 0.0f);
}
-ccl_device int bsdf_phong_ramp_sample(const ShaderClosure *sc,
+ccl_device int bsdf_phong_ramp_sample(ccl_private const ShaderClosure *sc,
float3 Ng,
float3 I,
float3 dIdx,
float3 dIdy,
float randu,
float randv,
- float3 *eval,
- float3 *omega_in,
- float3 *domega_in_dx,
- float3 *domega_in_dy,
- float *pdf)
+ ccl_private float3 *eval,
+ ccl_private float3 *omega_in,
+ ccl_private float3 *domega_in_dx,
+ ccl_private float3 *domega_in_dy,
+ ccl_private float *pdf)
{
- const PhongRampBsdf *bsdf = (const PhongRampBsdf *)sc;
+ ccl_private const PhongRampBsdf *bsdf = (ccl_private const PhongRampBsdf *)sc;
float cosNO = dot(bsdf->N, I);
float m_exponent = bsdf->exponent;
diff --git a/intern/cycles/kernel/closure/bsdf_principled_diffuse.h b/intern/cycles/kernel/closure/bsdf_principled_diffuse.h
index a72af519482..69376c1294d 100644
--- a/intern/cycles/kernel/closure/bsdf_principled_diffuse.h
+++ b/intern/cycles/kernel/closure/bsdf_principled_diffuse.h
@@ -19,64 +19,123 @@
/* DISNEY PRINCIPLED DIFFUSE BRDF
*
* Shading model by Brent Burley (Disney): "Physically Based Shading at Disney" (2012)
+ *
+ * "Extending the Disney BRDF to a BSDF with Integrated Subsurface Scattering" (2015)
+ * For the separation of retro-reflection, "2.3 Dielectric BRDF with integrated
+ * subsurface scattering"
*/
#include "kernel/closure/bsdf_util.h"
+#include "kernel/sample/mapping.h"
+
CCL_NAMESPACE_BEGIN
-typedef ccl_addr_space struct PrincipledDiffuseBsdf {
+enum PrincipledDiffuseBsdfComponents {
+ PRINCIPLED_DIFFUSE_FULL = 1,
+ PRINCIPLED_DIFFUSE_LAMBERT = 2,
+ PRINCIPLED_DIFFUSE_LAMBERT_EXIT = 4,
+ PRINCIPLED_DIFFUSE_RETRO_REFLECTION = 8,
+};
+
+typedef struct PrincipledDiffuseBsdf {
SHADER_CLOSURE_BASE;
float roughness;
+ int components;
} PrincipledDiffuseBsdf;
static_assert(sizeof(ShaderClosure) >= sizeof(PrincipledDiffuseBsdf),
"PrincipledDiffuseBsdf is too large!");
-ccl_device float3 calculate_principled_diffuse_brdf(
- const PrincipledDiffuseBsdf *bsdf, float3 N, float3 V, float3 L, float3 H, float *pdf)
+ccl_device int bsdf_principled_diffuse_setup(ccl_private PrincipledDiffuseBsdf *bsdf)
{
- float NdotL = dot(N, L);
- float NdotV = dot(N, V);
+ bsdf->type = CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID;
+ bsdf->components = PRINCIPLED_DIFFUSE_FULL;
+ return SD_BSDF | SD_BSDF_HAS_EVAL;
+}
- if (NdotL <= 0 || NdotV <= 0) {
- *pdf = 0.0f;
+ccl_device float3
+bsdf_principled_diffuse_compute_brdf(ccl_private const PrincipledDiffuseBsdf *bsdf,
+ float3 N,
+ float3 V,
+ float3 L,
+ ccl_private float *pdf)
+{
+ const float NdotL = dot(N, L);
+
+ if (NdotL <= 0) {
return make_float3(0.0f, 0.0f, 0.0f);
}
- float LdotH = dot(L, H);
+ const float NdotV = dot(N, V);
+
+ const float FV = schlick_fresnel(NdotV);
+ const float FL = schlick_fresnel(NdotL);
+
+ float f = 0.0f;
- float FL = schlick_fresnel(NdotL), FV = schlick_fresnel(NdotV);
- const float Fd90 = 0.5f + 2.0f * LdotH * LdotH * bsdf->roughness;
- float Fd = (1.0f * (1.0f - FL) + Fd90 * FL) * (1.0f * (1.0f - FV) + Fd90 * FV);
+ /* Lambertian component. */
+ if (bsdf->components & (PRINCIPLED_DIFFUSE_FULL | PRINCIPLED_DIFFUSE_LAMBERT)) {
+ f += (1.0f - 0.5f * FV) * (1.0f - 0.5f * FL);
+ }
+ else if (bsdf->components & PRINCIPLED_DIFFUSE_LAMBERT_EXIT) {
+ f += (1.0f - 0.5f * FL);
+ }
+
+ /* Retro-reflection component. */
+ if (bsdf->components & (PRINCIPLED_DIFFUSE_FULL | PRINCIPLED_DIFFUSE_RETRO_REFLECTION)) {
+ /* H = normalize(L + V); // Bisector of an angle between L and V
+ * LH2 = 2 * dot(L, H)^2 = 2cos(x)^2 = cos(2x) + 1 = dot(L, V) + 1,
+ * half-angle x between L and V is at most 90 deg. */
+ const float LH2 = dot(L, V) + 1;
+ const float RR = bsdf->roughness * LH2;
+ f += RR * (FL + FV + FL * FV * (RR - 1.0f));
+ }
- float value = M_1_PI_F * NdotL * Fd;
+ float value = M_1_PI_F * NdotL * f;
return make_float3(value, value, value);
}
-ccl_device int bsdf_principled_diffuse_setup(PrincipledDiffuseBsdf *bsdf)
+/* Compute Fresnel at entry point, to be combined with #PRINCIPLED_DIFFUSE_LAMBERT_EXIT
+ * at the exit point to get the complete BSDF. */
+ccl_device_inline float bsdf_principled_diffuse_compute_entry_fresnel(const float NdotV)
+{
+ const float FV = schlick_fresnel(NdotV);
+ return (1.0f - 0.5f * FV);
+}
+
+/* Ad-hoc weight adjustment to avoid retro-reflection taking away half the
+ * samples from BSSRDF. */
+ccl_device_inline float bsdf_principled_diffuse_retro_reflection_sample_weight(
+ ccl_private PrincipledDiffuseBsdf *bsdf, const float3 I)
+{
+ return bsdf->roughness * schlick_fresnel(dot(bsdf->N, I));
+}
+
+ccl_device int bsdf_principled_diffuse_setup(ccl_private PrincipledDiffuseBsdf *bsdf,
+ int components)
{
bsdf->type = CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID;
+ bsdf->components = components;
return SD_BSDF | SD_BSDF_HAS_EVAL;
}
-ccl_device float3 bsdf_principled_diffuse_eval_reflect(const ShaderClosure *sc,
+ccl_device float3 bsdf_principled_diffuse_eval_reflect(ccl_private const ShaderClosure *sc,
const float3 I,
const float3 omega_in,
- float *pdf)
+ ccl_private float *pdf)
{
- const PrincipledDiffuseBsdf *bsdf = (const PrincipledDiffuseBsdf *)sc;
+ ccl_private const PrincipledDiffuseBsdf *bsdf = (ccl_private const PrincipledDiffuseBsdf *)sc;
float3 N = bsdf->N;
float3 V = I; // outgoing
float3 L = omega_in; // incoming
- float3 H = normalize(L + V);
if (dot(N, omega_in) > 0.0f) {
*pdf = fmaxf(dot(N, omega_in), 0.0f) * M_1_PI_F;
- return calculate_principled_diffuse_brdf(bsdf, N, V, L, H, pdf);
+ return bsdf_principled_diffuse_compute_brdf(bsdf, N, V, L, pdf);
}
else {
*pdf = 0.0f;
@@ -84,37 +143,35 @@ ccl_device float3 bsdf_principled_diffuse_eval_reflect(const ShaderClosure *sc,
}
}
-ccl_device float3 bsdf_principled_diffuse_eval_transmit(const ShaderClosure *sc,
+ccl_device float3 bsdf_principled_diffuse_eval_transmit(ccl_private const ShaderClosure *sc,
const float3 I,
const float3 omega_in,
- float *pdf)
+ ccl_private float *pdf)
{
return make_float3(0.0f, 0.0f, 0.0f);
}
-ccl_device int bsdf_principled_diffuse_sample(const ShaderClosure *sc,
+ccl_device int bsdf_principled_diffuse_sample(ccl_private const ShaderClosure *sc,
float3 Ng,
float3 I,
float3 dIdx,
float3 dIdy,
float randu,
float randv,
- float3 *eval,
- float3 *omega_in,
- float3 *domega_in_dx,
- float3 *domega_in_dy,
- float *pdf)
+ ccl_private float3 *eval,
+ ccl_private float3 *omega_in,
+ ccl_private float3 *domega_in_dx,
+ ccl_private float3 *domega_in_dy,
+ ccl_private float *pdf)
{
- const PrincipledDiffuseBsdf *bsdf = (const PrincipledDiffuseBsdf *)sc;
+ ccl_private const PrincipledDiffuseBsdf *bsdf = (ccl_private const PrincipledDiffuseBsdf *)sc;
float3 N = bsdf->N;
sample_cos_hemisphere(N, randu, randv, omega_in, pdf);
if (dot(Ng, *omega_in) > 0) {
- float3 H = normalize(I + *omega_in);
-
- *eval = calculate_principled_diffuse_brdf(bsdf, N, I, *omega_in, H, pdf);
+ *eval = bsdf_principled_diffuse_compute_brdf(bsdf, N, I, *omega_in, pdf);
#ifdef __RAY_DIFFERENTIALS__
// TODO: find a better approximation for the diffuse bounce
diff --git a/intern/cycles/kernel/closure/bsdf_principled_sheen.h b/intern/cycles/kernel/closure/bsdf_principled_sheen.h
index 60ce7e4eb75..cc0a5accb95 100644
--- a/intern/cycles/kernel/closure/bsdf_principled_sheen.h
+++ b/intern/cycles/kernel/closure/bsdf_principled_sheen.h
@@ -25,7 +25,7 @@
CCL_NAMESPACE_BEGIN
-typedef ccl_addr_space struct PrincipledSheenBsdf {
+typedef struct PrincipledSheenBsdf {
SHADER_CLOSURE_BASE;
float avg_value;
} PrincipledSheenBsdf;
@@ -46,7 +46,7 @@ ccl_device_inline float calculate_avg_principled_sheen_brdf(float3 N, float3 I)
}
ccl_device float3
-calculate_principled_sheen_brdf(float3 N, float3 V, float3 L, float3 H, float *pdf)
+calculate_principled_sheen_brdf(float3 N, float3 V, float3 L, float3 H, ccl_private float *pdf)
{
float NdotL = dot(N, L);
float NdotV = dot(N, V);
@@ -63,7 +63,8 @@ calculate_principled_sheen_brdf(float3 N, float3 V, float3 L, float3 H, float *p
return make_float3(value, value, value);
}
-ccl_device int bsdf_principled_sheen_setup(const ShaderData *sd, PrincipledSheenBsdf *bsdf)
+ccl_device int bsdf_principled_sheen_setup(ccl_private const ShaderData *sd,
+ ccl_private PrincipledSheenBsdf *bsdf)
{
bsdf->type = CLOSURE_BSDF_PRINCIPLED_SHEEN_ID;
bsdf->avg_value = calculate_avg_principled_sheen_brdf(bsdf->N, sd->I);
@@ -71,12 +72,12 @@ ccl_device int bsdf_principled_sheen_setup(const ShaderData *sd, PrincipledSheen
return SD_BSDF | SD_BSDF_HAS_EVAL;
}
-ccl_device float3 bsdf_principled_sheen_eval_reflect(const ShaderClosure *sc,
+ccl_device float3 bsdf_principled_sheen_eval_reflect(ccl_private const ShaderClosure *sc,
const float3 I,
const float3 omega_in,
- float *pdf)
+ ccl_private float *pdf)
{
- const PrincipledSheenBsdf *bsdf = (const PrincipledSheenBsdf *)sc;
+ ccl_private const PrincipledSheenBsdf *bsdf = (ccl_private const PrincipledSheenBsdf *)sc;
float3 N = bsdf->N;
float3 V = I; // outgoing
@@ -93,28 +94,28 @@ ccl_device float3 bsdf_principled_sheen_eval_reflect(const ShaderClosure *sc,
}
}
-ccl_device float3 bsdf_principled_sheen_eval_transmit(const ShaderClosure *sc,
+ccl_device float3 bsdf_principled_sheen_eval_transmit(ccl_private const ShaderClosure *sc,
const float3 I,
const float3 omega_in,
- float *pdf)
+ ccl_private float *pdf)
{
return make_float3(0.0f, 0.0f, 0.0f);
}
-ccl_device int bsdf_principled_sheen_sample(const ShaderClosure *sc,
+ccl_device int bsdf_principled_sheen_sample(ccl_private const ShaderClosure *sc,
float3 Ng,
float3 I,
float3 dIdx,
float3 dIdy,
float randu,
float randv,
- float3 *eval,
- float3 *omega_in,
- float3 *domega_in_dx,
- float3 *domega_in_dy,
- float *pdf)
+ ccl_private float3 *eval,
+ ccl_private float3 *omega_in,
+ ccl_private float3 *domega_in_dx,
+ ccl_private float3 *domega_in_dy,
+ ccl_private float *pdf)
{
- const PrincipledSheenBsdf *bsdf = (const PrincipledSheenBsdf *)sc;
+ ccl_private const PrincipledSheenBsdf *bsdf = (ccl_private const PrincipledSheenBsdf *)sc;
float3 N = bsdf->N;
diff --git a/intern/cycles/kernel/closure/bsdf_reflection.h b/intern/cycles/kernel/closure/bsdf_reflection.h
index 31283971d5a..758bfd2b2d0 100644
--- a/intern/cycles/kernel/closure/bsdf_reflection.h
+++ b/intern/cycles/kernel/closure/bsdf_reflection.h
@@ -36,42 +36,42 @@ CCL_NAMESPACE_BEGIN
/* REFLECTION */
-ccl_device int bsdf_reflection_setup(MicrofacetBsdf *bsdf)
+ccl_device int bsdf_reflection_setup(ccl_private MicrofacetBsdf *bsdf)
{
bsdf->type = CLOSURE_BSDF_REFLECTION_ID;
return SD_BSDF;
}
-ccl_device float3 bsdf_reflection_eval_reflect(const ShaderClosure *sc,
+ccl_device float3 bsdf_reflection_eval_reflect(ccl_private const ShaderClosure *sc,
const float3 I,
const float3 omega_in,
- float *pdf)
+ ccl_private float *pdf)
{
return make_float3(0.0f, 0.0f, 0.0f);
}
-ccl_device float3 bsdf_reflection_eval_transmit(const ShaderClosure *sc,
+ccl_device float3 bsdf_reflection_eval_transmit(ccl_private const ShaderClosure *sc,
const float3 I,
const float3 omega_in,
- float *pdf)
+ ccl_private float *pdf)
{
return make_float3(0.0f, 0.0f, 0.0f);
}
-ccl_device int bsdf_reflection_sample(const ShaderClosure *sc,
+ccl_device int bsdf_reflection_sample(ccl_private const ShaderClosure *sc,
float3 Ng,
float3 I,
float3 dIdx,
float3 dIdy,
float randu,
float randv,
- float3 *eval,
- float3 *omega_in,
- float3 *domega_in_dx,
- float3 *domega_in_dy,
- float *pdf)
+ ccl_private float3 *eval,
+ ccl_private float3 *omega_in,
+ ccl_private float3 *domega_in_dx,
+ ccl_private float3 *domega_in_dy,
+ ccl_private float *pdf)
{
- const MicrofacetBsdf *bsdf = (const MicrofacetBsdf *)sc;
+ ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc;
float3 N = bsdf->N;
// only one direction is possible
diff --git a/intern/cycles/kernel/closure/bsdf_refraction.h b/intern/cycles/kernel/closure/bsdf_refraction.h
index cfedb5dfe2c..74e149b059e 100644
--- a/intern/cycles/kernel/closure/bsdf_refraction.h
+++ b/intern/cycles/kernel/closure/bsdf_refraction.h
@@ -36,42 +36,42 @@ CCL_NAMESPACE_BEGIN
/* REFRACTION */
-ccl_device int bsdf_refraction_setup(MicrofacetBsdf *bsdf)
+ccl_device int bsdf_refraction_setup(ccl_private MicrofacetBsdf *bsdf)
{
bsdf->type = CLOSURE_BSDF_REFRACTION_ID;
return SD_BSDF;
}
-ccl_device float3 bsdf_refraction_eval_reflect(const ShaderClosure *sc,
+ccl_device float3 bsdf_refraction_eval_reflect(ccl_private const ShaderClosure *sc,
const float3 I,
const float3 omega_in,
- float *pdf)
+ ccl_private float *pdf)
{
return make_float3(0.0f, 0.0f, 0.0f);
}
-ccl_device float3 bsdf_refraction_eval_transmit(const ShaderClosure *sc,
+ccl_device float3 bsdf_refraction_eval_transmit(ccl_private const ShaderClosure *sc,
const float3 I,
const float3 omega_in,
- float *pdf)
+ ccl_private float *pdf)
{
return make_float3(0.0f, 0.0f, 0.0f);
}
-ccl_device int bsdf_refraction_sample(const ShaderClosure *sc,
+ccl_device int bsdf_refraction_sample(ccl_private const ShaderClosure *sc,
float3 Ng,
float3 I,
float3 dIdx,
float3 dIdy,
float randu,
float randv,
- float3 *eval,
- float3 *omega_in,
- float3 *domega_in_dx,
- float3 *domega_in_dy,
- float *pdf)
+ ccl_private float3 *eval,
+ ccl_private float3 *omega_in,
+ ccl_private float3 *domega_in_dx,
+ ccl_private float3 *domega_in_dy,
+ ccl_private float *pdf)
{
- const MicrofacetBsdf *bsdf = (const MicrofacetBsdf *)sc;
+ ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc;
float m_eta = bsdf->ior;
float3 N = bsdf->N;
diff --git a/intern/cycles/kernel/closure/bsdf_toon.h b/intern/cycles/kernel/closure/bsdf_toon.h
index acdafe0f735..20f3b8f0074 100644
--- a/intern/cycles/kernel/closure/bsdf_toon.h
+++ b/intern/cycles/kernel/closure/bsdf_toon.h
@@ -34,7 +34,7 @@
CCL_NAMESPACE_BEGIN
-typedef ccl_addr_space struct ToonBsdf {
+typedef struct ToonBsdf {
SHADER_CLOSURE_BASE;
float size;
@@ -45,11 +45,11 @@ static_assert(sizeof(ShaderClosure) >= sizeof(ToonBsdf), "ToonBsdf is too large!
/* DIFFUSE TOON */
-ccl_device int bsdf_diffuse_toon_setup(ToonBsdf *bsdf)
+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;
}
@@ -73,12 +73,12 @@ ccl_device float bsdf_toon_get_sample_angle(float max_angle, float smooth)
return fminf(max_angle + smooth, M_PI_2_F);
}
-ccl_device float3 bsdf_diffuse_toon_eval_reflect(const ShaderClosure *sc,
+ccl_device float3 bsdf_diffuse_toon_eval_reflect(ccl_private const ShaderClosure *sc,
const float3 I,
const float3 omega_in,
- float *pdf)
+ ccl_private float *pdf)
{
- const ToonBsdf *bsdf = (const ToonBsdf *)sc;
+ ccl_private const ToonBsdf *bsdf = (ccl_private const ToonBsdf *)sc;
float max_angle = bsdf->size * M_PI_2_F;
float smooth = bsdf->smooth * M_PI_2_F;
float angle = safe_acosf(fmaxf(dot(bsdf->N, omega_in), 0.0f));
@@ -95,28 +95,28 @@ ccl_device float3 bsdf_diffuse_toon_eval_reflect(const ShaderClosure *sc,
return make_float3(0.0f, 0.0f, 0.0f);
}
-ccl_device float3 bsdf_diffuse_toon_eval_transmit(const ShaderClosure *sc,
+ccl_device float3 bsdf_diffuse_toon_eval_transmit(ccl_private const ShaderClosure *sc,
const float3 I,
const float3 omega_in,
- float *pdf)
+ ccl_private float *pdf)
{
return make_float3(0.0f, 0.0f, 0.0f);
}
-ccl_device int bsdf_diffuse_toon_sample(const ShaderClosure *sc,
+ccl_device int bsdf_diffuse_toon_sample(ccl_private const ShaderClosure *sc,
float3 Ng,
float3 I,
float3 dIdx,
float3 dIdy,
float randu,
float randv,
- float3 *eval,
- float3 *omega_in,
- float3 *domega_in_dx,
- float3 *domega_in_dy,
- float *pdf)
+ ccl_private float3 *eval,
+ ccl_private float3 *omega_in,
+ ccl_private float3 *domega_in_dx,
+ ccl_private float3 *domega_in_dy,
+ ccl_private float *pdf)
{
- const ToonBsdf *bsdf = (const ToonBsdf *)sc;
+ ccl_private const ToonBsdf *bsdf = (ccl_private const ToonBsdf *)sc;
float max_angle = bsdf->size * M_PI_2_F;
float smooth = bsdf->smooth * M_PI_2_F;
float sample_angle = bsdf_toon_get_sample_angle(max_angle, smooth);
@@ -143,21 +143,21 @@ ccl_device int bsdf_diffuse_toon_sample(const ShaderClosure *sc,
/* GLOSSY TOON */
-ccl_device int bsdf_glossy_toon_setup(ToonBsdf *bsdf)
+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;
}
-ccl_device float3 bsdf_glossy_toon_eval_reflect(const ShaderClosure *sc,
+ccl_device float3 bsdf_glossy_toon_eval_reflect(ccl_private const ShaderClosure *sc,
const float3 I,
const float3 omega_in,
- float *pdf)
+ ccl_private float *pdf)
{
- const ToonBsdf *bsdf = (const ToonBsdf *)sc;
+ ccl_private const ToonBsdf *bsdf = (ccl_private const ToonBsdf *)sc;
float max_angle = bsdf->size * M_PI_2_F;
float smooth = bsdf->smooth * M_PI_2_F;
float cosNI = dot(bsdf->N, omega_in);
@@ -180,28 +180,28 @@ ccl_device float3 bsdf_glossy_toon_eval_reflect(const ShaderClosure *sc,
return make_float3(0.0f, 0.0f, 0.0f);
}
-ccl_device float3 bsdf_glossy_toon_eval_transmit(const ShaderClosure *sc,
+ccl_device float3 bsdf_glossy_toon_eval_transmit(ccl_private const ShaderClosure *sc,
const float3 I,
const float3 omega_in,
- float *pdf)
+ ccl_private float *pdf)
{
return make_float3(0.0f, 0.0f, 0.0f);
}
-ccl_device int bsdf_glossy_toon_sample(const ShaderClosure *sc,
+ccl_device int bsdf_glossy_toon_sample(ccl_private const ShaderClosure *sc,
float3 Ng,
float3 I,
float3 dIdx,
float3 dIdy,
float randu,
float randv,
- float3 *eval,
- float3 *omega_in,
- float3 *domega_in_dx,
- float3 *domega_in_dy,
- float *pdf)
+ ccl_private float3 *eval,
+ ccl_private float3 *omega_in,
+ ccl_private float3 *domega_in_dx,
+ ccl_private float3 *domega_in_dy,
+ ccl_private float *pdf)
{
- const ToonBsdf *bsdf = (const ToonBsdf *)sc;
+ ccl_private const ToonBsdf *bsdf = (ccl_private const ToonBsdf *)sc;
float max_angle = bsdf->size * M_PI_2_F;
float smooth = bsdf->smooth * M_PI_2_F;
float cosNO = dot(bsdf->N, I);
diff --git a/intern/cycles/kernel/closure/bsdf_transparent.h b/intern/cycles/kernel/closure/bsdf_transparent.h
index f1dc7efb345..e801b6ea1a3 100644
--- a/intern/cycles/kernel/closure/bsdf_transparent.h
+++ b/intern/cycles/kernel/closure/bsdf_transparent.h
@@ -34,7 +34,9 @@
CCL_NAMESPACE_BEGIN
-ccl_device void bsdf_transparent_setup(ShaderData *sd, const float3 weight, int path_flag)
+ccl_device void bsdf_transparent_setup(ccl_private ShaderData *sd,
+ const float3 weight,
+ uint32_t path_flag)
{
/* Check cutoff weight. */
float sample_weight = fabsf(average(weight));
@@ -47,7 +49,7 @@ ccl_device void bsdf_transparent_setup(ShaderData *sd, const float3 weight, int
/* Add weight to existing transparent BSDF. */
for (int i = 0; i < sd->num_closure; i++) {
- ShaderClosure *sc = &sd->closure[i];
+ ccl_private ShaderClosure *sc = &sd->closure[i];
if (sc->type == CLOSURE_BSDF_TRANSPARENT_ID) {
sc->weight += weight;
@@ -68,7 +70,7 @@ ccl_device void bsdf_transparent_setup(ShaderData *sd, const float3 weight, int
}
/* Create new transparent BSDF. */
- ShaderClosure *bsdf = closure_alloc(
+ ccl_private ShaderClosure *bsdf = closure_alloc(
sd, sizeof(ShaderClosure), CLOSURE_BSDF_TRANSPARENT_ID, weight);
if (bsdf) {
@@ -81,34 +83,34 @@ ccl_device void bsdf_transparent_setup(ShaderData *sd, const float3 weight, int
}
}
-ccl_device float3 bsdf_transparent_eval_reflect(const ShaderClosure *sc,
+ccl_device float3 bsdf_transparent_eval_reflect(ccl_private const ShaderClosure *sc,
const float3 I,
const float3 omega_in,
- float *pdf)
+ ccl_private float *pdf)
{
return make_float3(0.0f, 0.0f, 0.0f);
}
-ccl_device float3 bsdf_transparent_eval_transmit(const ShaderClosure *sc,
+ccl_device float3 bsdf_transparent_eval_transmit(ccl_private const ShaderClosure *sc,
const float3 I,
const float3 omega_in,
- float *pdf)
+ ccl_private float *pdf)
{
return make_float3(0.0f, 0.0f, 0.0f);
}
-ccl_device int bsdf_transparent_sample(const ShaderClosure *sc,
+ccl_device int bsdf_transparent_sample(ccl_private const ShaderClosure *sc,
float3 Ng,
float3 I,
float3 dIdx,
float3 dIdy,
float randu,
float randv,
- float3 *eval,
- float3 *omega_in,
- float3 *domega_in_dx,
- float3 *domega_in_dy,
- float *pdf)
+ ccl_private float3 *eval,
+ ccl_private float3 *omega_in,
+ ccl_private float3 *domega_in_dx,
+ ccl_private float3 *domega_in_dy,
+ ccl_private float *pdf)
{
// only one direction is possible
*omega_in = -I;
diff --git a/intern/cycles/kernel/closure/bsdf_util.h b/intern/cycles/kernel/closure/bsdf_util.h
index beec5f768a1..b1c16a037df 100644
--- a/intern/cycles/kernel/closure/bsdf_util.h
+++ b/intern/cycles/kernel/closure/bsdf_util.h
@@ -37,17 +37,17 @@ CCL_NAMESPACE_BEGIN
ccl_device float fresnel_dielectric(float eta,
const float3 N,
const float3 I,
- float3 *R,
- float3 *T,
+ ccl_private float3 *R,
+ ccl_private float3 *T,
#ifdef __RAY_DIFFERENTIALS__
const float3 dIdx,
const float3 dIdy,
- float3 *dRdx,
- float3 *dRdy,
- float3 *dTdx,
- float3 *dTdy,
+ ccl_private float3 *dRdx,
+ ccl_private float3 *dRdy,
+ ccl_private float3 *dTdx,
+ ccl_private float3 *dTdy,
#endif
- bool *is_inside)
+ ccl_private bool *is_inside)
{
float cos = dot(N, I), neta;
float3 Nn;
@@ -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/closure/bssrdf.h b/intern/cycles/kernel/closure/bssrdf.h
index e095314678a..9df69e073c1 100644
--- a/intern/cycles/kernel/closure/bssrdf.h
+++ b/intern/cycles/kernel/closure/bssrdf.h
@@ -18,7 +18,7 @@
CCL_NAMESPACE_BEGIN
-typedef ccl_addr_space struct Bssrdf {
+typedef struct Bssrdf {
SHADER_CLOSURE_BASE;
float3 radius;
@@ -29,6 +29,8 @@ typedef ccl_addr_space struct Bssrdf {
static_assert(sizeof(ShaderClosure) >= sizeof(Bssrdf), "Bssrdf is too large!");
+/* Random Walk BSSRDF */
+
ccl_device float bssrdf_dipole_compute_Rd(float alpha_prime, float fourthirdA)
{
float s = sqrtf(3.0f * (1.0f - alpha_prime));
@@ -64,9 +66,11 @@ ccl_device float bssrdf_dipole_compute_alpha_prime(float rd, float fourthirdA)
return xmid;
}
-ccl_device void bssrdf_setup_radius(Bssrdf *bssrdf, const ClosureType type, const float eta)
+ccl_device void bssrdf_setup_radius(ccl_private Bssrdf *bssrdf,
+ const ClosureType type,
+ const float eta)
{
- if (type == CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID) {
+ if (type == CLOSURE_BSSRDF_BURLEY_ID || type == CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID) {
/* Scale mean free path length so it gives similar looking result to older
* Cubic, Gaussian and Burley models. */
bssrdf->radius *= 0.25f * M_1_PI_F;
@@ -87,11 +91,188 @@ ccl_device void bssrdf_setup_radius(Bssrdf *bssrdf, const ClosureType type, cons
}
}
+/* Christensen-Burley BSSRDF.
+ *
+ * Approximate Reflectance Profiles from
+ * http://graphics.pixar.com/library/ApproxBSSRDF/paper.pdf
+ */
+
+/* This is a bit arbitrary, just need big enough radius so it matches
+ * the mean free length, but still not too big so sampling is still
+ * effective. */
+#define BURLEY_TRUNCATE 16.0f
+#define BURLEY_TRUNCATE_CDF 0.9963790093708328f // cdf(BURLEY_TRUNCATE)
+
+ccl_device_inline float bssrdf_burley_fitting(float A)
+{
+ /* Diffuse surface transmission, equation (6). */
+ return 1.9f - A + 3.5f * (A - 0.8f) * (A - 0.8f);
+}
+
+/* Scale mean free path length so it gives similar looking result
+ * to Cubic and Gaussian models. */
+ccl_device_inline float3 bssrdf_burley_compatible_mfp(float3 r)
+{
+ return 0.25f * M_1_PI_F * r;
+}
+
+ccl_device void bssrdf_burley_setup(ccl_private Bssrdf *bssrdf)
+{
+ /* Mean free path length. */
+ const float3 l = bssrdf_burley_compatible_mfp(bssrdf->radius);
+ /* Surface albedo. */
+ const float3 A = bssrdf->albedo;
+ const float3 s = make_float3(
+ bssrdf_burley_fitting(A.x), bssrdf_burley_fitting(A.y), bssrdf_burley_fitting(A.z));
+
+ bssrdf->radius = l / s;
+}
+
+ccl_device float bssrdf_burley_eval(const float d, float r)
+{
+ const float Rm = BURLEY_TRUNCATE * d;
+
+ if (r >= Rm)
+ return 0.0f;
+
+ /* Burley reflectance profile, equation (3).
+ *
+ * NOTES:
+ * - Surface albedo is already included into `sc->weight`, no need to
+ * multiply by this term here.
+ * - This is normalized diffuse model, so the equation is multiplied
+ * by `2*pi`, which also matches `cdf()`.
+ */
+ float exp_r_3_d = expf(-r / (3.0f * d));
+ float exp_r_d = exp_r_3_d * exp_r_3_d * exp_r_3_d;
+ return (exp_r_d + exp_r_3_d) / (4.0f * d);
+}
+
+ccl_device float bssrdf_burley_pdf(const float d, float r)
+{
+ if (r == 0.0f) {
+ return 0.0f;
+ }
+
+ return bssrdf_burley_eval(d, r) * (1.0f / BURLEY_TRUNCATE_CDF);
+}
+
+/* Find the radius for desired CDF value.
+ * Returns scaled radius, meaning the result is to be scaled up by d.
+ * Since there's no closed form solution we do Newton-Raphson method to find it.
+ */
+ccl_device_forceinline float bssrdf_burley_root_find(float xi)
+{
+ const float tolerance = 1e-6f;
+ const int max_iteration_count = 10;
+ /* Do initial guess based on manual curve fitting, this allows us to reduce
+ * number of iterations to maximum 4 across the [0..1] range. We keep maximum
+ * number of iteration higher just to be sure we didn't miss root in some
+ * corner case.
+ */
+ float r;
+ if (xi <= 0.9f) {
+ r = expf(xi * xi * 2.4f) - 1.0f;
+ }
+ else {
+ /* TODO(sergey): Some nicer curve fit is possible here. */
+ r = 15.0f;
+ }
+ /* Solve against scaled radius. */
+ for (int i = 0; i < max_iteration_count; i++) {
+ float exp_r_3 = expf(-r / 3.0f);
+ float exp_r = exp_r_3 * exp_r_3 * exp_r_3;
+ float f = 1.0f - 0.25f * exp_r - 0.75f * exp_r_3 - xi;
+ float f_ = 0.25f * exp_r + 0.25f * exp_r_3;
+
+ if (fabsf(f) < tolerance || f_ == 0.0f) {
+ break;
+ }
+
+ r = r - f / f_;
+ if (r < 0.0f) {
+ r = 0.0f;
+ }
+ }
+ return r;
+}
+
+ccl_device void bssrdf_burley_sample(const float d,
+ float xi,
+ ccl_private float *r,
+ ccl_private float *h)
+{
+ const float Rm = BURLEY_TRUNCATE * d;
+ const float r_ = bssrdf_burley_root_find(xi * BURLEY_TRUNCATE_CDF) * d;
+
+ *r = r_;
+
+ /* h^2 + r^2 = Rm^2 */
+ *h = safe_sqrtf(Rm * Rm - r_ * r_);
+}
+
+ccl_device float bssrdf_num_channels(const float3 radius)
+{
+ float channels = 0;
+ if (radius.x > 0.0f) {
+ channels += 1.0f;
+ }
+ if (radius.y > 0.0f) {
+ channels += 1.0f;
+ }
+ if (radius.z > 0.0f) {
+ channels += 1.0f;
+ }
+ return channels;
+}
+
+ccl_device void bssrdf_sample(const float3 radius,
+ float xi,
+ ccl_private float *r,
+ ccl_private float *h)
+{
+ const float num_channels = bssrdf_num_channels(radius);
+ float sampled_radius;
+
+ /* Sample color channel and reuse random number. Only a subset of channels
+ * may be used if their radius was too small to handle as BSSRDF. */
+ xi *= num_channels;
+
+ if (xi < 1.0f) {
+ sampled_radius = (radius.x > 0.0f) ? radius.x : (radius.y > 0.0f) ? radius.y : radius.z;
+ }
+ else if (xi < 2.0f) {
+ xi -= 1.0f;
+ sampled_radius = (radius.x > 0.0f && radius.y > 0.0f) ? radius.y : radius.z;
+ }
+ else {
+ xi -= 2.0f;
+ sampled_radius = radius.z;
+ }
+
+ /* Sample BSSRDF. */
+ bssrdf_burley_sample(sampled_radius, xi, r, h);
+}
+
+ccl_device_forceinline float3 bssrdf_eval(const float3 radius, float r)
+{
+ return make_float3(bssrdf_burley_pdf(radius.x, r),
+ bssrdf_burley_pdf(radius.y, r),
+ bssrdf_burley_pdf(radius.z, r));
+}
+
+ccl_device_forceinline float bssrdf_pdf(const float3 radius, float r)
+{
+ float3 pdf = bssrdf_eval(radius, r);
+ return (pdf.x + pdf.y + pdf.z) / bssrdf_num_channels(radius);
+}
+
/* Setup */
-ccl_device_inline Bssrdf *bssrdf_alloc(ShaderData *sd, float3 weight)
+ccl_device_inline ccl_private Bssrdf *bssrdf_alloc(ccl_private ShaderData *sd, float3 weight)
{
- Bssrdf *bssrdf = (Bssrdf *)closure_alloc(sd, sizeof(Bssrdf), CLOSURE_NONE_ID, weight);
+ ccl_private Bssrdf *bssrdf = (ccl_private Bssrdf *)closure_alloc(
+ sd, sizeof(Bssrdf), CLOSURE_NONE_ID, weight);
if (bssrdf == NULL) {
return NULL;
@@ -102,13 +283,33 @@ ccl_device_inline Bssrdf *bssrdf_alloc(ShaderData *sd, float3 weight)
return (sample_weight >= CLOSURE_WEIGHT_CUTOFF) ? bssrdf : NULL;
}
-ccl_device int bssrdf_setup(ShaderData *sd, Bssrdf *bssrdf, ClosureType type, const float ior)
+ccl_device int bssrdf_setup(ccl_private ShaderData *sd,
+ ccl_private Bssrdf *bssrdf,
+ ClosureType type,
+ const float ior)
{
int flag = 0;
+
+ /* Add retro-reflection component as separate diffuse BSDF. */
+ if (bssrdf->roughness != FLT_MAX) {
+ ccl_private PrincipledDiffuseBsdf *bsdf = (ccl_private PrincipledDiffuseBsdf *)bsdf_alloc(
+ sd, sizeof(PrincipledDiffuseBsdf), bssrdf->weight);
+
+ if (bsdf) {
+ bsdf->N = bssrdf->N;
+ bsdf->roughness = bssrdf->roughness;
+ flag |= bsdf_principled_diffuse_setup(bsdf, PRINCIPLED_DIFFUSE_RETRO_REFLECTION);
+
+ /* Ad-hoc weight adjustment to avoid retro-reflection taking away half the
+ * samples from BSSRDF. */
+ bsdf->sample_weight *= bsdf_principled_diffuse_retro_reflection_sample_weight(bsdf, sd->I);
+ }
+ }
+
+ /* Verify if the radii are large enough to sample without precision issues. */
int bssrdf_channels = 3;
float3 diffuse_weight = make_float3(0.0f, 0.0f, 0.0f);
- /* Verify if the radii are large enough to sample without precision issues. */
if (bssrdf->radius.x < BSSRDF_MIN_RADIUS) {
diffuse_weight.x = bssrdf->weight.x;
bssrdf->weight.x = 0.0f;
@@ -132,26 +333,22 @@ ccl_device int bssrdf_setup(ShaderData *sd, Bssrdf *bssrdf, ClosureType type, co
/* Add diffuse BSDF if any radius too small. */
#ifdef __PRINCIPLED__
if (bssrdf->roughness != FLT_MAX) {
- float roughness = bssrdf->roughness;
- float3 N = bssrdf->N;
-
- PrincipledDiffuseBsdf *bsdf = (PrincipledDiffuseBsdf *)bsdf_alloc(
+ ccl_private PrincipledDiffuseBsdf *bsdf = (ccl_private PrincipledDiffuseBsdf *)bsdf_alloc(
sd, sizeof(PrincipledDiffuseBsdf), diffuse_weight);
if (bsdf) {
- bsdf->type = CLOSURE_BSDF_BSSRDF_PRINCIPLED_ID;
- bsdf->N = N;
- bsdf->roughness = roughness;
- flag |= bsdf_principled_diffuse_setup(bsdf);
+ bsdf->N = bssrdf->N;
+ bsdf->roughness = bssrdf->roughness;
+ flag |= bsdf_principled_diffuse_setup(bsdf, PRINCIPLED_DIFFUSE_LAMBERT);
}
}
else
#endif /* __PRINCIPLED__ */
{
- DiffuseBsdf *bsdf = (DiffuseBsdf *)bsdf_alloc(sd, sizeof(DiffuseBsdf), diffuse_weight);
+ ccl_private DiffuseBsdf *bsdf = (ccl_private DiffuseBsdf *)bsdf_alloc(
+ sd, sizeof(DiffuseBsdf), diffuse_weight);
if (bsdf) {
- bsdf->type = CLOSURE_BSDF_BSSRDF_ID;
bsdf->N = bssrdf->N;
flag |= bsdf_diffuse_setup(bsdf);
}
diff --git a/intern/cycles/kernel/closure/emissive.h b/intern/cycles/kernel/closure/emissive.h
index a2519d97618..3d56e989522 100644
--- a/intern/cycles/kernel/closure/emissive.h
+++ b/intern/cycles/kernel/closure/emissive.h
@@ -36,7 +36,7 @@ CCL_NAMESPACE_BEGIN
/* BACKGROUND CLOSURE */
-ccl_device void background_setup(ShaderData *sd, const float3 weight)
+ccl_device void background_setup(ccl_private ShaderData *sd, const float3 weight)
{
if (sd->flag & SD_EMISSION) {
sd->closure_emission_background += weight;
@@ -49,7 +49,7 @@ ccl_device void background_setup(ShaderData *sd, const float3 weight)
/* EMISSION CLOSURE */
-ccl_device void emission_setup(ShaderData *sd, const float3 weight)
+ccl_device void emission_setup(ccl_private ShaderData *sd, const float3 weight)
{
if (sd->flag & SD_EMISSION) {
sd->closure_emission_background += weight;
@@ -69,8 +69,11 @@ ccl_device float emissive_pdf(const float3 Ng, const float3 I)
return (cosNO > 0.0f) ? 1.0f : 0.0f;
}
-ccl_device void emissive_sample(
- const float3 Ng, float randu, float randv, float3 *omega_out, float *pdf)
+ccl_device void emissive_sample(const float3 Ng,
+ float randu,
+ float randv,
+ ccl_private float3 *omega_out,
+ ccl_private float *pdf)
{
/* todo: not implemented and used yet */
}
diff --git a/intern/cycles/kernel/closure/volume.h b/intern/cycles/kernel/closure/volume.h
index 69959a3f21b..4a7a63819ab 100644
--- a/intern/cycles/kernel/closure/volume.h
+++ b/intern/cycles/kernel/closure/volume.h
@@ -20,7 +20,7 @@ CCL_NAMESPACE_BEGIN
/* VOLUME EXTINCTION */
-ccl_device void volume_extinction_setup(ShaderData *sd, float3 weight)
+ccl_device void volume_extinction_setup(ccl_private ShaderData *sd, float3 weight)
{
if (sd->flag & SD_EXTINCTION) {
sd->closure_transparent_extinction += weight;
@@ -33,7 +33,7 @@ ccl_device void volume_extinction_setup(ShaderData *sd, float3 weight)
/* HENYEY-GREENSTEIN CLOSURE */
-typedef ccl_addr_space struct HenyeyGreensteinVolume {
+typedef struct HenyeyGreensteinVolume {
SHADER_CLOSURE_BASE;
float g;
@@ -51,7 +51,7 @@ ccl_device float single_peaked_henyey_greenstein(float cos_theta, float g)
(M_1_PI_F * 0.25f);
};
-ccl_device int volume_henyey_greenstein_setup(HenyeyGreensteinVolume *volume)
+ccl_device int volume_henyey_greenstein_setup(ccl_private HenyeyGreensteinVolume *volume)
{
volume->type = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID;
@@ -61,10 +61,10 @@ ccl_device int volume_henyey_greenstein_setup(HenyeyGreensteinVolume *volume)
return SD_SCATTER;
}
-ccl_device float3 volume_henyey_greenstein_eval_phase(const ShaderVolumeClosure *svc,
+ccl_device float3 volume_henyey_greenstein_eval_phase(ccl_private const ShaderVolumeClosure *svc,
const float3 I,
float3 omega_in,
- float *pdf)
+ ccl_private float *pdf)
{
float g = svc->g;
@@ -81,7 +81,7 @@ ccl_device float3 volume_henyey_greenstein_eval_phase(const ShaderVolumeClosure
}
ccl_device float3
-henyey_greenstrein_sample(float3 D, float g, float randu, float randv, float *pdf)
+henyey_greenstrein_sample(float3 D, float g, float randu, float randv, ccl_private float *pdf)
{
/* match pdf for small g */
float cos_theta;
@@ -112,17 +112,17 @@ henyey_greenstrein_sample(float3 D, float g, float randu, float randv, float *pd
return dir;
}
-ccl_device int volume_henyey_greenstein_sample(const ShaderVolumeClosure *svc,
+ccl_device int volume_henyey_greenstein_sample(ccl_private const ShaderVolumeClosure *svc,
float3 I,
float3 dIdx,
float3 dIdy,
float randu,
float randv,
- float3 *eval,
- float3 *omega_in,
- float3 *domega_in_dx,
- float3 *domega_in_dy,
- float *pdf)
+ ccl_private float3 *eval,
+ ccl_private float3 *omega_in,
+ ccl_private float3 *domega_in_dx,
+ ccl_private float3 *domega_in_dy,
+ ccl_private float *pdf)
{
float g = svc->g;
@@ -141,22 +141,22 @@ ccl_device int volume_henyey_greenstein_sample(const ShaderVolumeClosure *svc,
/* VOLUME CLOSURE */
-ccl_device float3 volume_phase_eval(const ShaderData *sd,
- const ShaderVolumeClosure *svc,
+ccl_device float3 volume_phase_eval(ccl_private const ShaderData *sd,
+ ccl_private const ShaderVolumeClosure *svc,
float3 omega_in,
- float *pdf)
+ ccl_private float *pdf)
{
return volume_henyey_greenstein_eval_phase(svc, sd->I, omega_in, pdf);
}
-ccl_device int volume_phase_sample(const ShaderData *sd,
- const ShaderVolumeClosure *svc,
+ccl_device int volume_phase_sample(ccl_private const ShaderData *sd,
+ ccl_private const ShaderVolumeClosure *svc,
float randu,
float randv,
- float3 *eval,
- float3 *omega_in,
- differential3 *domega_in,
- float *pdf)
+ ccl_private float3 *eval,
+ ccl_private float3 *omega_in,
+ ccl_private differential3 *domega_in,
+ ccl_private float *pdf)
{
return volume_henyey_greenstein_sample(svc,
sd->I,
@@ -187,7 +187,10 @@ ccl_device float volume_channel_get(float3 value, int channel)
return (channel == 0) ? value.x : ((channel == 1) ? value.y : value.z);
}
-ccl_device int volume_sample_channel(float3 albedo, float3 throughput, float rand, float3 *pdf)
+ccl_device int volume_sample_channel(float3 albedo,
+ float3 throughput,
+ float rand,
+ ccl_private float3 *pdf)
{
/* Sample color channel proportional to throughput and single scattering
* albedo, to significantly reduce noise with many bounce, following:
@@ -196,22 +199,18 @@ ccl_device int volume_sample_channel(float3 albedo, float3 throughput, float ran
* Tracing". Matt Jen-Yuan Chiang, Peter Kutz, Brent Burley. SIGGRAPH 2016. */
float3 weights = fabs(throughput * albedo);
float sum_weights = weights.x + weights.y + weights.z;
- float3 weights_pdf;
if (sum_weights > 0.0f) {
- weights_pdf = weights / sum_weights;
+ *pdf = weights / sum_weights;
}
else {
- weights_pdf = make_float3(1.0f / 3.0f, 1.0f / 3.0f, 1.0f / 3.0f);
+ *pdf = make_float3(1.0f / 3.0f, 1.0f / 3.0f, 1.0f / 3.0f);
}
- *pdf = weights_pdf;
-
- /* OpenCL does not support -> on float3, so don't use pdf->x. */
- if (rand < weights_pdf.x) {
+ if (rand < pdf->x) {
return 0;
}
- else if (rand < weights_pdf.x + weights_pdf.y) {
+ else if (rand < pdf->x + pdf->y) {
return 1;
}
else {
diff --git a/intern/cycles/kernel/device/cpu/compat.h b/intern/cycles/kernel/device/cpu/compat.h
index bfd936c7bbd..5ccca52255f 100644
--- a/intern/cycles/kernel/device/cpu/compat.h
+++ b/intern/cycles/kernel/device/cpu/compat.h
@@ -26,13 +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"
-
-#define ccl_addr_space
+#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 98b036e269d..746e48b9880 100644
--- a/intern/cycles/kernel/device/cpu/globals.h
+++ b/intern/cycles/kernel/device/cpu/globals.h
@@ -18,8 +18,9 @@
#pragma once
-#include "kernel/kernel_profiling.h"
-#include "kernel/kernel_types.h"
+#include "kernel/tables.h"
+#include "kernel/types.h"
+#include "kernel/util/profiling.h"
CCL_NAMESPACE_BEGIN
@@ -34,9 +35,9 @@ struct OSLThreadData;
struct OSLShadingSystem;
#endif
-typedef struct KernelGlobals {
+typedef struct KernelGlobalsCPU {
#define KERNEL_TEX(type, name) texture<type> name;
-#include "kernel/kernel_textures.h"
+#include "kernel/textures.h"
KernelData __data;
@@ -51,7 +52,9 @@ typedef struct KernelGlobals {
/* **** Run-time data **** */
ProfilingState profiler;
-} KernelGlobals;
+} KernelGlobalsCPU;
+
+typedef const KernelGlobalsCPU *ccl_restrict KernelGlobals;
/* Abstraction macros */
#define kernel_tex_fetch(tex, index) (kg->tex.fetch(index))
diff --git a/intern/cycles/kernel/device/cpu/image.h b/intern/cycles/kernel/device/cpu/image.h
index 57e81ab186d..93f956e354d 100644
--- a/intern/cycles/kernel/device/cpu/image.h
+++ b/intern/cycles/kernel/device/cpu/image.h
@@ -72,12 +72,12 @@ template<typename T> struct TextureInterpolator {
static ccl_always_inline float4 read(half4 r)
{
- return half4_to_float4(r);
+ return half4_to_float4_image(r);
}
static ccl_always_inline float4 read(half r)
{
- float f = half_to_float(r);
+ float f = half_to_float_image(r);
return make_float4(f, f, f, 1.0f);
}
@@ -583,7 +583,7 @@ template<typename T> struct NanoVDBInterpolator {
#undef SET_CUBIC_SPLINE_WEIGHTS
-ccl_device float4 kernel_tex_image_interp(const KernelGlobals *kg, int id, float x, float y)
+ccl_device float4 kernel_tex_image_interp(KernelGlobals kg, int id, float x, float y)
{
const TextureInfo &info = kernel_tex_fetch(__texture_info, id);
@@ -611,7 +611,7 @@ ccl_device float4 kernel_tex_image_interp(const KernelGlobals *kg, int id, float
}
}
-ccl_device float4 kernel_tex_image_interp_3d(const KernelGlobals *kg,
+ccl_device float4 kernel_tex_image_interp_3d(KernelGlobals kg,
int id,
float3 P,
InterpolationType interp)
diff --git a/intern/cycles/kernel/device/cpu/kernel.cpp b/intern/cycles/kernel/device/cpu/kernel.cpp
index ac1cdf5fffe..a16c637d5ac 100644
--- a/intern/cycles/kernel/device/cpu/kernel.cpp
+++ b/intern/cycles/kernel/device/cpu/kernel.cpp
@@ -64,7 +64,7 @@ CCL_NAMESPACE_BEGIN
/* Memory Copy */
-void kernel_const_copy(KernelGlobals *kg, const char *name, void *host, size_t)
+void kernel_const_copy(KernelGlobalsCPU *kg, const char *name, void *host, size_t)
{
if (strcmp(name, "__data") == 0) {
kg->__data = *(KernelData *)host;
@@ -74,7 +74,7 @@ void kernel_const_copy(KernelGlobals *kg, const char *name, void *host, size_t)
}
}
-void kernel_global_memory_copy(KernelGlobals *kg, const char *name, void *mem, size_t size)
+void kernel_global_memory_copy(KernelGlobalsCPU *kg, const char *name, void *mem, size_t size)
{
if (0) {
}
@@ -85,7 +85,7 @@ void kernel_global_memory_copy(KernelGlobals *kg, const char *name, void *mem, s
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 ae2a841835a..6af8094b1ea 100644
--- a/intern/cycles/kernel/device/cpu/kernel.h
+++ b/intern/cycles/kernel/device/cpu/kernel.h
@@ -18,9 +18,10 @@
/* CPU Kernel Interface */
-#include "util/util_types.h"
+#include "util/half.h"
+#include "util/types.h"
-#include "kernel/kernel_types.h"
+#include "kernel/types.h"
CCL_NAMESPACE_BEGIN
@@ -29,17 +30,17 @@ CCL_NAMESPACE_BEGIN
#define KERNEL_FUNCTION_FULL_NAME(name) KERNEL_NAME_EVAL(KERNEL_ARCH, name)
struct IntegratorStateCPU;
-struct KernelGlobals;
+struct KernelGlobalsCPU;
struct KernelData;
-KernelGlobals *kernel_globals_create();
-void kernel_globals_free(KernelGlobals *kg);
+KernelGlobalsCPU *kernel_globals_create();
+void kernel_globals_free(KernelGlobalsCPU *kg);
-void *kernel_osl_memory(const KernelGlobals *kg);
-bool kernel_osl_use(const KernelGlobals *kg);
+void *kernel_osl_memory(const KernelGlobalsCPU *kg);
+bool kernel_osl_use(const KernelGlobalsCPU *kg);
-void kernel_const_copy(KernelGlobals *kg, const char *name, void *host, size_t size);
-void kernel_global_memory_copy(KernelGlobals *kg, const char *name, void *mem, size_t size);
+void kernel_const_copy(KernelGlobalsCPU *kg, const char *name, void *host, size_t size);
+void kernel_global_memory_copy(KernelGlobalsCPU *kg, const char *name, void *mem, size_t size);
#define KERNEL_ARCH cpu
#include "kernel/device/cpu/kernel_arch.h"
diff --git a/intern/cycles/kernel/device/cpu/kernel_arch.h b/intern/cycles/kernel/device/cpu/kernel_arch.h
index 81f328c710b..61f62f3136b 100644
--- a/intern/cycles/kernel/device/cpu/kernel_arch.h
+++ b/intern/cycles/kernel/device/cpu/kernel_arch.h
@@ -21,23 +21,23 @@
*/
#define KERNEL_INTEGRATOR_FUNCTION(name) \
- void KERNEL_FUNCTION_FULL_NAME(integrator_##name)(const KernelGlobals *ccl_restrict kg, \
+ void KERNEL_FUNCTION_FULL_NAME(integrator_##name)(const KernelGlobalsCPU *ccl_restrict kg, \
IntegratorStateCPU *state)
#define KERNEL_INTEGRATOR_SHADE_FUNCTION(name) \
- void KERNEL_FUNCTION_FULL_NAME(integrator_##name)(const KernelGlobals *ccl_restrict kg, \
+ void KERNEL_FUNCTION_FULL_NAME(integrator_##name)(const KernelGlobalsCPU *ccl_restrict kg, \
IntegratorStateCPU *state, \
ccl_global float *render_buffer)
#define KERNEL_INTEGRATOR_INIT_FUNCTION(name) \
- bool KERNEL_FUNCTION_FULL_NAME(integrator_##name)(const KernelGlobals *ccl_restrict kg, \
+ bool KERNEL_FUNCTION_FULL_NAME(integrator_##name)(const KernelGlobalsCPU *ccl_restrict kg, \
IntegratorStateCPU *state, \
KernelWorkTile *tile, \
ccl_global float *render_buffer)
KERNEL_INTEGRATOR_INIT_FUNCTION(init_from_camera);
KERNEL_INTEGRATOR_INIT_FUNCTION(init_from_bake);
-KERNEL_INTEGRATOR_FUNCTION(intersect_closest);
+KERNEL_INTEGRATOR_SHADE_FUNCTION(intersect_closest);
KERNEL_INTEGRATOR_FUNCTION(intersect_shadow);
KERNEL_INTEGRATOR_FUNCTION(intersect_subsurface);
KERNEL_INTEGRATOR_FUNCTION(intersect_volume_stack);
@@ -52,25 +52,61 @@ KERNEL_INTEGRATOR_SHADE_FUNCTION(megakernel);
#undef KERNEL_INTEGRATOR_INIT_FUNCTION
#undef KERNEL_INTEGRATOR_SHADE_FUNCTION
+#define KERNEL_FILM_CONVERT_FUNCTION(name) \
+ void KERNEL_FUNCTION_FULL_NAME(film_convert_##name)(const KernelFilmConvert *kfilm_convert, \
+ const float *buffer, \
+ float *pixel, \
+ const int width, \
+ const int buffer_stride, \
+ const int pixel_stride); \
+ void KERNEL_FUNCTION_FULL_NAME(film_convert_half_rgba_##name)( \
+ const KernelFilmConvert *kfilm_convert, \
+ const float *buffer, \
+ half4 *pixel, \
+ const int width, \
+ const int buffer_stride);
+
+KERNEL_FILM_CONVERT_FUNCTION(depth)
+KERNEL_FILM_CONVERT_FUNCTION(mist)
+KERNEL_FILM_CONVERT_FUNCTION(sample_count)
+KERNEL_FILM_CONVERT_FUNCTION(float)
+
+KERNEL_FILM_CONVERT_FUNCTION(light_path)
+KERNEL_FILM_CONVERT_FUNCTION(float3)
+
+KERNEL_FILM_CONVERT_FUNCTION(motion)
+KERNEL_FILM_CONVERT_FUNCTION(cryptomatte)
+KERNEL_FILM_CONVERT_FUNCTION(shadow_catcher)
+KERNEL_FILM_CONVERT_FUNCTION(shadow_catcher_matte_with_shadow)
+KERNEL_FILM_CONVERT_FUNCTION(combined)
+KERNEL_FILM_CONVERT_FUNCTION(float4)
+
+#undef KERNEL_FILM_CONVERT_FUNCTION
+
/* --------------------------------------------------------------------
* Shader evaluation.
*/
-void KERNEL_FUNCTION_FULL_NAME(shader_eval_background)(const KernelGlobals *kg,
+void KERNEL_FUNCTION_FULL_NAME(shader_eval_background)(const KernelGlobalsCPU *kg,
const KernelShaderEvalInput *input,
- float4 *output,
+ float *output,
const int offset);
-void KERNEL_FUNCTION_FULL_NAME(shader_eval_displace)(const KernelGlobals *kg,
+void KERNEL_FUNCTION_FULL_NAME(shader_eval_displace)(const KernelGlobalsCPU *kg,
const KernelShaderEvalInput *input,
- float4 *output,
+ float *output,
const int offset);
+void KERNEL_FUNCTION_FULL_NAME(shader_eval_curve_shadow_transparency)(
+ const KernelGlobalsCPU *kg,
+ const KernelShaderEvalInput *input,
+ float *output,
+ const int offset);
/* --------------------------------------------------------------------
* Adaptive sampling.
*/
bool KERNEL_FUNCTION_FULL_NAME(adaptive_sampling_convergence_check)(
- const KernelGlobals *kg,
+ const KernelGlobalsCPU *kg,
ccl_global float *render_buffer,
int x,
int y,
@@ -79,14 +115,14 @@ bool KERNEL_FUNCTION_FULL_NAME(adaptive_sampling_convergence_check)(
int offset,
int stride);
-void KERNEL_FUNCTION_FULL_NAME(adaptive_sampling_filter_x)(const KernelGlobals *kg,
+void KERNEL_FUNCTION_FULL_NAME(adaptive_sampling_filter_x)(const KernelGlobalsCPU *kg,
ccl_global float *render_buffer,
int y,
int start_x,
int width,
int offset,
int stride);
-void KERNEL_FUNCTION_FULL_NAME(adaptive_sampling_filter_y)(const KernelGlobals *kg,
+void KERNEL_FUNCTION_FULL_NAME(adaptive_sampling_filter_y)(const KernelGlobalsCPU *kg,
ccl_global float *render_buffer,
int x,
int start_y,
@@ -98,16 +134,8 @@ void KERNEL_FUNCTION_FULL_NAME(adaptive_sampling_filter_y)(const KernelGlobals *
* Cryptomatte.
*/
-void KERNEL_FUNCTION_FULL_NAME(cryptomatte_postprocess)(const KernelGlobals *kg,
+void KERNEL_FUNCTION_FULL_NAME(cryptomatte_postprocess)(const KernelGlobalsCPU *kg,
ccl_global float *render_buffer,
int pixel_index);
-/* --------------------------------------------------------------------
- * Bake.
- */
-/* TODO(sergey): Needs to be re-implemented. Or not? Brecht did it already :) */
-
-void KERNEL_FUNCTION_FULL_NAME(bake)(
- const KernelGlobals *kg, float *buffer, int sample, int x, int y, int offset, int stride);
-
#undef KERNEL_ARCH
diff --git a/intern/cycles/kernel/device/cpu/kernel_arch_impl.h b/intern/cycles/kernel/device/cpu/kernel_arch_impl.h
index 1432abfd330..747c47c34c9 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/id_passes.h"
+# include "kernel/film/read.h"
+
+# include "kernel/bake/bake.h"
#else
# define STUB_ASSERT(arch, name) \
@@ -69,8 +70,20 @@ CCL_NAMESPACE_BEGIN
# define KERNEL_INVOKE(name, ...) integrator_##name(__VA_ARGS__)
#endif
+/* TODO: Either use something like get_work_pixel(), or simplify tile which is passed here, so
+ * that it does not contain unused fields. */
+#define DEFINE_INTEGRATOR_INIT_KERNEL(name) \
+ bool KERNEL_FUNCTION_FULL_NAME(integrator_##name)(const KernelGlobalsCPU *kg, \
+ IntegratorStateCPU *state, \
+ KernelWorkTile *tile, \
+ ccl_global float *render_buffer) \
+ { \
+ return KERNEL_INVOKE( \
+ name, kg, state, tile, render_buffer, tile->x, tile->y, tile->start_sample); \
+ }
+
#define DEFINE_INTEGRATOR_KERNEL(name) \
- void KERNEL_FUNCTION_FULL_NAME(integrator_##name)(const KernelGlobals *kg, \
+ void KERNEL_FUNCTION_FULL_NAME(integrator_##name)(const KernelGlobalsCPU *kg, \
IntegratorStateCPU *state) \
{ \
KERNEL_INVOKE(name, kg, state); \
@@ -78,43 +91,45 @@ CCL_NAMESPACE_BEGIN
#define DEFINE_INTEGRATOR_SHADE_KERNEL(name) \
void KERNEL_FUNCTION_FULL_NAME(integrator_##name)( \
- const KernelGlobals *kg, IntegratorStateCPU *state, ccl_global float *render_buffer) \
+ const KernelGlobalsCPU *kg, IntegratorStateCPU *state, ccl_global float *render_buffer) \
{ \
KERNEL_INVOKE(name, kg, state, render_buffer); \
}
-/* TODO: Either use something like get_work_pixel(), or simplify tile which is passed here, so
- * that it does not contain unused fields. */
-#define DEFINE_INTEGRATOR_INIT_KERNEL(name) \
- bool KERNEL_FUNCTION_FULL_NAME(integrator_##name)(const KernelGlobals *kg, \
- IntegratorStateCPU *state, \
- KernelWorkTile *tile, \
- ccl_global float *render_buffer) \
+#define DEFINE_INTEGRATOR_SHADOW_KERNEL(name) \
+ void KERNEL_FUNCTION_FULL_NAME(integrator_##name)(const KernelGlobalsCPU *kg, \
+ IntegratorStateCPU *state) \
{ \
- return KERNEL_INVOKE( \
- name, kg, state, tile, render_buffer, tile->x, tile->y, tile->start_sample); \
+ KERNEL_INVOKE(name, kg, &state->shadow); \
+ }
+
+#define DEFINE_INTEGRATOR_SHADOW_SHADE_KERNEL(name) \
+ void KERNEL_FUNCTION_FULL_NAME(integrator_##name)( \
+ const KernelGlobalsCPU *kg, IntegratorStateCPU *state, ccl_global float *render_buffer) \
+ { \
+ KERNEL_INVOKE(name, kg, &state->shadow, render_buffer); \
}
DEFINE_INTEGRATOR_INIT_KERNEL(init_from_camera)
DEFINE_INTEGRATOR_INIT_KERNEL(init_from_bake)
-DEFINE_INTEGRATOR_KERNEL(intersect_closest)
-DEFINE_INTEGRATOR_KERNEL(intersect_shadow)
+DEFINE_INTEGRATOR_SHADE_KERNEL(intersect_closest)
DEFINE_INTEGRATOR_KERNEL(intersect_subsurface)
DEFINE_INTEGRATOR_KERNEL(intersect_volume_stack)
DEFINE_INTEGRATOR_SHADE_KERNEL(shade_background)
DEFINE_INTEGRATOR_SHADE_KERNEL(shade_light)
-DEFINE_INTEGRATOR_SHADE_KERNEL(shade_shadow)
DEFINE_INTEGRATOR_SHADE_KERNEL(shade_surface)
DEFINE_INTEGRATOR_SHADE_KERNEL(shade_volume)
DEFINE_INTEGRATOR_SHADE_KERNEL(megakernel)
+DEFINE_INTEGRATOR_SHADOW_KERNEL(intersect_shadow)
+DEFINE_INTEGRATOR_SHADOW_SHADE_KERNEL(shade_shadow)
/* --------------------------------------------------------------------
* Shader evaluation.
*/
-void KERNEL_FUNCTION_FULL_NAME(shader_eval_displace)(const KernelGlobals *kg,
+void KERNEL_FUNCTION_FULL_NAME(shader_eval_displace)(const KernelGlobalsCPU *kg,
const KernelShaderEvalInput *input,
- float4 *output,
+ float *output,
const int offset)
{
#ifdef KERNEL_STUB
@@ -124,9 +139,9 @@ void KERNEL_FUNCTION_FULL_NAME(shader_eval_displace)(const KernelGlobals *kg,
#endif
}
-void KERNEL_FUNCTION_FULL_NAME(shader_eval_background)(const KernelGlobals *kg,
+void KERNEL_FUNCTION_FULL_NAME(shader_eval_background)(const KernelGlobalsCPU *kg,
const KernelShaderEvalInput *input,
- float4 *output,
+ float *output,
const int offset)
{
#ifdef KERNEL_STUB
@@ -136,12 +151,25 @@ void KERNEL_FUNCTION_FULL_NAME(shader_eval_background)(const KernelGlobals *kg,
#endif
}
+void KERNEL_FUNCTION_FULL_NAME(shader_eval_curve_shadow_transparency)(
+ const KernelGlobalsCPU *kg,
+ const KernelShaderEvalInput *input,
+ float *output,
+ const int offset)
+{
+#ifdef KERNEL_STUB
+ STUB_ASSERT(KERNEL_ARCH, shader_eval_curve_shadow_transparency);
+#else
+ kernel_curve_shadow_transparency_evaluate(kg, input, output, offset);
+#endif
+}
+
/* --------------------------------------------------------------------
* Adaptive sampling.
*/
bool KERNEL_FUNCTION_FULL_NAME(adaptive_sampling_convergence_check)(
- const KernelGlobals *kg,
+ const KernelGlobalsCPU *kg,
ccl_global float *render_buffer,
int x,
int y,
@@ -159,7 +187,7 @@ bool KERNEL_FUNCTION_FULL_NAME(adaptive_sampling_convergence_check)(
#endif
}
-void KERNEL_FUNCTION_FULL_NAME(adaptive_sampling_filter_x)(const KernelGlobals *kg,
+void KERNEL_FUNCTION_FULL_NAME(adaptive_sampling_filter_x)(const KernelGlobalsCPU *kg,
ccl_global float *render_buffer,
int y,
int start_x,
@@ -174,7 +202,7 @@ void KERNEL_FUNCTION_FULL_NAME(adaptive_sampling_filter_x)(const KernelGlobals *
#endif
}
-void KERNEL_FUNCTION_FULL_NAME(adaptive_sampling_filter_y)(const KernelGlobals *kg,
+void KERNEL_FUNCTION_FULL_NAME(adaptive_sampling_filter_y)(const KernelGlobalsCPU *kg,
ccl_global float *render_buffer,
int x,
int start_y,
@@ -193,7 +221,7 @@ void KERNEL_FUNCTION_FULL_NAME(adaptive_sampling_filter_y)(const KernelGlobals *
* Cryptomatte.
*/
-void KERNEL_FUNCTION_FULL_NAME(cryptomatte_postprocess)(const KernelGlobals *kg,
+void KERNEL_FUNCTION_FULL_NAME(cryptomatte_postprocess)(const KernelGlobalsCPU *kg,
ccl_global float *render_buffer,
int pixel_index)
{
@@ -205,23 +233,83 @@ void KERNEL_FUNCTION_FULL_NAME(cryptomatte_postprocess)(const KernelGlobals *kg,
}
/* --------------------------------------------------------------------
- * Bake.
+ * Film Convert.
*/
-/* TODO(sergey): Needs to be re-implemented. Or not? Brecht did it already :) */
-void KERNEL_FUNCTION_FULL_NAME(bake)(
- const KernelGlobals *kg, float *buffer, int sample, int x, int y, int offset, int stride)
-{
-#if 0
-# ifdef KERNEL_STUB
- STUB_ASSERT(KERNEL_ARCH, bake);
-# else
-# ifdef __BAKING__
- kernel_bake_evaluate(kg, buffer, sample, x, y, offset, stride);
-# endif
-# endif /* KERNEL_STUB */
+#ifdef KERNEL_STUB
+
+# define KERNEL_FILM_CONVERT_FUNCTION(name, is_float) \
+ void KERNEL_FUNCTION_FULL_NAME(film_convert_##name)(const KernelFilmConvert *kfilm_convert, \
+ const float *buffer, \
+ float *pixel, \
+ const int width, \
+ const int buffer_stride, \
+ const int pixel_stride) \
+ { \
+ STUB_ASSERT(KERNEL_ARCH, film_convert_##name); \
+ } \
+ void KERNEL_FUNCTION_FULL_NAME(film_convert_half_rgba_##name)( \
+ const KernelFilmConvert *kfilm_convert, \
+ const float *buffer, \
+ half4 *pixel, \
+ const int width, \
+ const int buffer_stride) \
+ { \
+ STUB_ASSERT(KERNEL_ARCH, film_convert_##name); \
+ }
+
+#else
+
+# define KERNEL_FILM_CONVERT_FUNCTION(name, is_float) \
+ void KERNEL_FUNCTION_FULL_NAME(film_convert_##name)(const KernelFilmConvert *kfilm_convert, \
+ const float *buffer, \
+ float *pixel, \
+ const int width, \
+ const int buffer_stride, \
+ const int pixel_stride) \
+ { \
+ for (int i = 0; i < width; i++, buffer += buffer_stride, pixel += pixel_stride) { \
+ film_get_pass_pixel_##name(kfilm_convert, buffer, pixel); \
+ } \
+ } \
+ void KERNEL_FUNCTION_FULL_NAME(film_convert_half_rgba_##name)( \
+ const KernelFilmConvert *kfilm_convert, \
+ const float *buffer, \
+ half4 *pixel, \
+ const int width, \
+ const int buffer_stride) \
+ { \
+ for (int i = 0; i < width; i++, buffer += buffer_stride, pixel++) { \
+ float pixel_rgba[4] = {0.0f, 0.0f, 0.0f, 1.0f}; \
+ film_get_pass_pixel_##name(kfilm_convert, buffer, pixel_rgba); \
+ if (is_float) { \
+ pixel_rgba[1] = pixel_rgba[0]; \
+ pixel_rgba[2] = pixel_rgba[0]; \
+ } \
+ film_apply_pass_pixel_overlays_rgba(kfilm_convert, buffer, pixel_rgba); \
+ *pixel = float4_to_half4_display( \
+ make_float4(pixel_rgba[0], pixel_rgba[1], pixel_rgba[2], pixel_rgba[3])); \
+ } \
+ }
+
#endif
-}
+
+KERNEL_FILM_CONVERT_FUNCTION(depth, true)
+KERNEL_FILM_CONVERT_FUNCTION(mist, true)
+KERNEL_FILM_CONVERT_FUNCTION(sample_count, true)
+KERNEL_FILM_CONVERT_FUNCTION(float, true)
+
+KERNEL_FILM_CONVERT_FUNCTION(light_path, false)
+KERNEL_FILM_CONVERT_FUNCTION(float3, false)
+
+KERNEL_FILM_CONVERT_FUNCTION(motion, false)
+KERNEL_FILM_CONVERT_FUNCTION(cryptomatte, false)
+KERNEL_FILM_CONVERT_FUNCTION(shadow_catcher, false)
+KERNEL_FILM_CONVERT_FUNCTION(shadow_catcher_matte_with_shadow, false)
+KERNEL_FILM_CONVERT_FUNCTION(combined, false)
+KERNEL_FILM_CONVERT_FUNCTION(float4, false)
+
+#undef KERNEL_FILM_CONVERT_FUNCTION
#undef KERNEL_INVOKE
#undef DEFINE_INTEGRATOR_KERNEL
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 3c85a8e7bd2..658dec102b1 100644
--- a/intern/cycles/kernel/device/cuda/compat.h
+++ b/intern/cycles/kernel/device/cuda/compat.h
@@ -52,14 +52,14 @@ typedef unsigned long long uint64_t;
#endif
#define ccl_device_noinline __device__ __noinline__
#define ccl_device_noinline_cpu ccl_device
+#define ccl_device_inline_method ccl_device
#define ccl_global
-#define ccl_static_constant __constant__
+#define ccl_inline_constant __constant__
#define ccl_device_constant __constant__ __device__
#define ccl_constant const
#define ccl_gpu_shared __shared__
#define ccl_private
#define ccl_may_alias
-#define ccl_addr_space
#define ccl_restrict __restrict__
#define ccl_loop_no_unroll
#define ccl_align(n) __align__(n)
@@ -76,6 +76,7 @@ typedef unsigned long long uint64_t;
#define ccl_gpu_block_idx_x (blockIdx.x)
#define ccl_gpu_grid_dim_x (gridDim.x)
#define ccl_gpu_warp_size (warpSize)
+#define ccl_gpu_thread_mask(thread_warp) uint(0xFFFFFFFF >> (ccl_gpu_warp_size - thread_warp))
#define ccl_gpu_global_id_x() (ccl_gpu_block_idx_x * ccl_gpu_block_dim_x + ccl_gpu_thread_idx_x)
#define ccl_gpu_global_size_x() (ccl_gpu_grid_dim_x * ccl_gpu_block_dim_x)
@@ -85,7 +86,6 @@ typedef unsigned long long uint64_t;
#define ccl_gpu_syncthreads() __syncthreads()
#define ccl_gpu_ballot(predicate) __ballot_sync(0xFFFFFFFF, predicate)
#define ccl_gpu_shfl_down_sync(mask, var, detla) __shfl_down_sync(mask, var, detla)
-#define ccl_gpu_popc(x) __popc(x)
/* GPU texture objects */
@@ -129,7 +129,14 @@ __device__ half __float2half(const float f)
return val;
}
+__device__ float __half2float(const half h)
+{
+ float val;
+ asm("{ cvt.f32.f16 %0, %1;}\n" : "=f"(val) : "h"(h));
+ return val;
+}
+
/* 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/config.h b/intern/cycles/kernel/device/cuda/config.h
index 46196dcdb51..003881d7912 100644
--- a/intern/cycles/kernel/device/cuda/config.h
+++ b/intern/cycles/kernel/device/cuda/config.h
@@ -92,12 +92,29 @@
/* Compute number of threads per block and minimum blocks per multiprocessor
* given the maximum number of registers per thread. */
-
#define ccl_gpu_kernel(block_num_threads, thread_num_registers) \
extern "C" __global__ void __launch_bounds__(block_num_threads, \
GPU_MULTIPRESSOR_MAX_REGISTERS / \
(block_num_threads * thread_num_registers))
+#define ccl_gpu_kernel_threads(block_num_threads) \
+ extern "C" __global__ void __launch_bounds__(block_num_threads)
+
+#define ccl_gpu_kernel_signature(name, ...) kernel_gpu_##name(__VA_ARGS__)
+
+#define ccl_gpu_kernel_call(x) x
+
+/* Define a function object where "func" is the lambda body, and additional parameters are used to
+ * specify captured state */
+#define ccl_gpu_kernel_lambda(func, ...) \
+ struct KernelLambda { \
+ __VA_ARGS__; \
+ __device__ int operator()(const int state) \
+ { \
+ return (func); \
+ } \
+ } ccl_gpu_kernel_lambda_pass
+
/* sanity checks */
#if GPU_KERNEL_BLOCK_NUM_THREADS > GPU_BLOCK_MAX_THREADS
diff --git a/intern/cycles/kernel/device/cuda/globals.h b/intern/cycles/kernel/device/cuda/globals.h
index 169047175f5..e5023fad40c 100644
--- a/intern/cycles/kernel/device/cuda/globals.h
+++ b/intern/cycles/kernel/device/cuda/globals.h
@@ -18,23 +18,25 @@
#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
/* Not actually used, just a NULL pointer that gets passed everywhere, which we
* hope gets optimized out by the compiler. */
-struct KernelGlobals {
+struct KernelGlobalsGPU {
int unused[1];
};
+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/image.h b/intern/cycles/kernel/device/gpu/image.h
index b015c78a8f5..0900a45c83d 100644
--- a/intern/cycles/kernel/device/gpu/image.h
+++ b/intern/cycles/kernel/device/gpu/image.h
@@ -65,7 +65,9 @@ ccl_device float cubic_h1(float a)
/* Fast bicubic texture lookup using 4 bilinear lookups, adapted from CUDA samples. */
template<typename T>
-ccl_device_noinline T kernel_tex_image_interp_bicubic(const TextureInfo &info, float x, float y)
+ccl_device_noinline T kernel_tex_image_interp_bicubic(ccl_global const TextureInfo &info,
+ float x,
+ float y)
{
ccl_gpu_tex_object tex = (ccl_gpu_tex_object)info.data;
@@ -94,7 +96,7 @@ ccl_device_noinline T kernel_tex_image_interp_bicubic(const TextureInfo &info, f
/* Fast tricubic texture lookup using 8 trilinear lookups. */
template<typename T>
ccl_device_noinline T
-kernel_tex_image_interp_tricubic(const TextureInfo &info, float x, float y, float z)
+kernel_tex_image_interp_tricubic(ccl_global const TextureInfo &info, float x, float y, float z)
{
ccl_gpu_tex_object tex = (ccl_gpu_tex_object)info.data;
@@ -169,7 +171,7 @@ ccl_device T kernel_tex_image_interp_tricubic_nanovdb(S &s, float x, float y, fl
template<typename T>
ccl_device_noinline T kernel_tex_image_interp_nanovdb(
- const TextureInfo &info, float x, float y, float z, uint interpolation)
+ ccl_global const TextureInfo &info, float x, float y, float z, uint interpolation)
{
using namespace nanovdb;
@@ -189,9 +191,9 @@ ccl_device_noinline T kernel_tex_image_interp_nanovdb(
}
#endif
-ccl_device float4 kernel_tex_image_interp(const KernelGlobals *kg, int id, float x, float y)
+ccl_device float4 kernel_tex_image_interp(KernelGlobals kg, int id, float x, float y)
{
- const TextureInfo &info = kernel_tex_fetch(__texture_info, id);
+ ccl_global const TextureInfo &info = kernel_tex_fetch(__texture_info, id);
/* float4, byte4, ushort4 and half4 */
const int texture_type = info.data_type;
@@ -221,12 +223,12 @@ ccl_device float4 kernel_tex_image_interp(const KernelGlobals *kg, int id, float
}
}
-ccl_device float4 kernel_tex_image_interp_3d(const KernelGlobals *kg,
+ccl_device float4 kernel_tex_image_interp_3d(KernelGlobals kg,
int id,
float3 P,
InterpolationType interp)
{
- const TextureInfo &info = kernel_tex_fetch(__texture_info, id);
+ ccl_global const TextureInfo &info = kernel_tex_fetch(__texture_info, id);
if (info.use_transform_3d) {
P = transform_point(&info.transform_3d, P);
diff --git a/intern/cycles/kernel/device/gpu/kernel.h b/intern/cycles/kernel/device/gpu/kernel.h
index 7b79c0aedfa..eed005803e2 100644
--- a/intern/cycles/kernel/device/gpu/kernel.h
+++ b/intern/cycles/kernel/device/gpu/kernel.h
@@ -20,47 +20,64 @@
#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/sample/lcg.h"
+
+/* Include constant tables before entering Metal's context class scope (context_begin.h) */
+#include "kernel/tables.h"
+
+#ifdef __KERNEL_METAL__
+# include "kernel/device/metal/context_begin.h"
+#endif
+
+#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"
+
+#ifdef __KERNEL_METAL__
+# include "kernel/device/metal/context_end.h"
+#endif
+
+#include "kernel/film/read.h"
/* --------------------------------------------------------------------
* Integrator.
*/
ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
- kernel_gpu_integrator_reset(int num_states)
+ ccl_gpu_kernel_signature(integrator_reset, int num_states)
{
const int state = ccl_gpu_global_id_x();
if (state < num_states) {
- INTEGRATOR_STATE_WRITE(path, queued_kernel) = 0;
- INTEGRATOR_STATE_WRITE(shadow_path, queued_kernel) = 0;
+ INTEGRATOR_STATE_WRITE(state, path, queued_kernel) = 0;
+ INTEGRATOR_STATE_WRITE(state, shadow_path, queued_kernel) = 0;
}
}
ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
- kernel_gpu_integrator_init_from_camera(KernelWorkTile *tiles,
- const int num_tiles,
- float *render_buffer,
- const int max_tile_work_size)
+ ccl_gpu_kernel_signature(integrator_init_from_camera,
+ ccl_global KernelWorkTile *tiles,
+ const int num_tiles,
+ ccl_global float *render_buffer,
+ const int max_tile_work_size)
{
const int work_index = ccl_gpu_global_id_x();
@@ -71,7 +88,7 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
const int tile_index = work_index / max_tile_work_size;
const int tile_work_index = work_index - tile_index * max_tile_work_size;
- const KernelWorkTile *tile = &tiles[tile_index];
+ ccl_global const KernelWorkTile *tile = &tiles[tile_index];
if (tile_work_index >= tile->work_size) {
return;
@@ -80,16 +97,18 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
const int state = tile->path_index_offset + tile_work_index;
uint x, y, sample;
- get_work_pixel(tile, tile_work_index, &x, &y, &sample);
+ ccl_gpu_kernel_call(get_work_pixel(tile, tile_work_index, &x, &y, &sample));
- integrator_init_from_camera(nullptr, state, tile, render_buffer, x, y, sample);
+ ccl_gpu_kernel_call(
+ integrator_init_from_camera(nullptr, state, tile, render_buffer, x, y, sample));
}
ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
- kernel_gpu_integrator_init_from_bake(KernelWorkTile *tiles,
- const int num_tiles,
- float *render_buffer,
- const int max_tile_work_size)
+ ccl_gpu_kernel_signature(integrator_init_from_bake,
+ ccl_global KernelWorkTile *tiles,
+ const int num_tiles,
+ ccl_global float *render_buffer,
+ const int max_tile_work_size)
{
const int work_index = ccl_gpu_global_id_x();
@@ -100,7 +119,7 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
const int tile_index = work_index / max_tile_work_size;
const int tile_work_index = work_index - tile_index * max_tile_work_size;
- const KernelWorkTile *tile = &tiles[tile_index];
+ ccl_global const KernelWorkTile *tile = &tiles[tile_index];
if (tile_work_index >= tile->work_size) {
return;
@@ -109,211 +128,312 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
const int state = tile->path_index_offset + tile_work_index;
uint x, y, sample;
- get_work_pixel(tile, tile_work_index, &x, &y, &sample);
+ ccl_gpu_kernel_call(get_work_pixel(tile, tile_work_index, &x, &y, &sample));
- integrator_init_from_bake(nullptr, state, tile, render_buffer, x, y, sample);
+ ccl_gpu_kernel_call(
+ integrator_init_from_bake(nullptr, state, tile, render_buffer, x, y, sample));
}
ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
- kernel_gpu_integrator_intersect_closest(const int *path_index_array, const int work_size)
+ ccl_gpu_kernel_signature(integrator_intersect_closest,
+ ccl_global const int *path_index_array,
+ ccl_global float *render_buffer,
+ const int work_size)
{
const int global_index = ccl_gpu_global_id_x();
if (global_index < work_size) {
const int state = (path_index_array) ? path_index_array[global_index] : global_index;
- integrator_intersect_closest(NULL, state);
+ ccl_gpu_kernel_call(integrator_intersect_closest(NULL, state, render_buffer));
}
}
ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
- kernel_gpu_integrator_intersect_shadow(const int *path_index_array, const int work_size)
+ ccl_gpu_kernel_signature(integrator_intersect_shadow,
+ ccl_global const int *path_index_array,
+ const int work_size)
{
const int global_index = ccl_gpu_global_id_x();
if (global_index < work_size) {
const int state = (path_index_array) ? path_index_array[global_index] : global_index;
- integrator_intersect_shadow(NULL, state);
+ ccl_gpu_kernel_call(integrator_intersect_shadow(NULL, state));
}
}
ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
- kernel_gpu_integrator_intersect_subsurface(const int *path_index_array, const int work_size)
+ ccl_gpu_kernel_signature(integrator_intersect_subsurface,
+ ccl_global const int *path_index_array,
+ const int work_size)
{
const int global_index = ccl_gpu_global_id_x();
if (global_index < work_size) {
const int state = (path_index_array) ? path_index_array[global_index] : global_index;
- integrator_intersect_subsurface(NULL, state);
+ ccl_gpu_kernel_call(integrator_intersect_subsurface(NULL, state));
}
}
ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
- kernel_gpu_integrator_intersect_volume_stack(const int *path_index_array, const int work_size)
+ ccl_gpu_kernel_signature(integrator_intersect_volume_stack,
+ ccl_global const int *path_index_array,
+ const int work_size)
{
const int global_index = ccl_gpu_global_id_x();
if (global_index < work_size) {
const int state = (path_index_array) ? path_index_array[global_index] : global_index;
- integrator_intersect_volume_stack(NULL, state);
+ ccl_gpu_kernel_call(integrator_intersect_volume_stack(NULL, state));
}
}
ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
- kernel_gpu_integrator_shade_background(const int *path_index_array,
- float *render_buffer,
- const int work_size)
+ ccl_gpu_kernel_signature(integrator_shade_background,
+ ccl_global const int *path_index_array,
+ ccl_global float *render_buffer,
+ const int work_size)
{
const int global_index = ccl_gpu_global_id_x();
if (global_index < work_size) {
const int state = (path_index_array) ? path_index_array[global_index] : global_index;
- integrator_shade_background(NULL, state, render_buffer);
+ ccl_gpu_kernel_call(integrator_shade_background(NULL, state, render_buffer));
}
}
ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
- kernel_gpu_integrator_shade_light(const int *path_index_array,
- float *render_buffer,
- const int work_size)
+ ccl_gpu_kernel_signature(integrator_shade_light,
+ ccl_global const int *path_index_array,
+ ccl_global float *render_buffer,
+ const int work_size)
{
const int global_index = ccl_gpu_global_id_x();
if (global_index < work_size) {
const int state = (path_index_array) ? path_index_array[global_index] : global_index;
- integrator_shade_light(NULL, state, render_buffer);
+ ccl_gpu_kernel_call(integrator_shade_light(NULL, state, render_buffer));
}
}
ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
- kernel_gpu_integrator_shade_shadow(const int *path_index_array,
- float *render_buffer,
- const int work_size)
+ ccl_gpu_kernel_signature(integrator_shade_shadow,
+ ccl_global const int *path_index_array,
+ ccl_global float *render_buffer,
+ const int work_size)
{
const int global_index = ccl_gpu_global_id_x();
if (global_index < work_size) {
const int state = (path_index_array) ? path_index_array[global_index] : global_index;
- integrator_shade_shadow(NULL, state, render_buffer);
+ ccl_gpu_kernel_call(integrator_shade_shadow(NULL, state, render_buffer));
}
}
ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
- kernel_gpu_integrator_shade_surface(const int *path_index_array,
- float *render_buffer,
- const int work_size)
+ ccl_gpu_kernel_signature(integrator_shade_surface,
+ ccl_global const int *path_index_array,
+ ccl_global float *render_buffer,
+ const int work_size)
{
const int global_index = ccl_gpu_global_id_x();
if (global_index < work_size) {
const int state = (path_index_array) ? path_index_array[global_index] : global_index;
- integrator_shade_surface(NULL, state, render_buffer);
+ ccl_gpu_kernel_call(integrator_shade_surface(NULL, state, render_buffer));
}
}
+#ifdef __KERNEL_METAL__
+constant int __dummy_constant [[function_constant(0)]];
+#endif
+
ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
- kernel_gpu_integrator_shade_surface_raytrace(const int *path_index_array,
- float *render_buffer,
- const int work_size)
+ ccl_gpu_kernel_signature(integrator_shade_surface_raytrace,
+ ccl_global const int *path_index_array,
+ ccl_global float *render_buffer,
+ const int work_size)
{
const int global_index = ccl_gpu_global_id_x();
if (global_index < work_size) {
const int state = (path_index_array) ? path_index_array[global_index] : global_index;
- integrator_shade_surface_raytrace(NULL, state, render_buffer);
+
+#ifdef __KERNEL_METAL__
+ KernelGlobals kg = NULL;
+ /* Workaround Ambient Occlusion and Bevel nodes not working with Metal.
+ * Dummy offset should not affect result, but somehow fixes bug! */
+ kg += __dummy_constant;
+ ccl_gpu_kernel_call(integrator_shade_surface_raytrace(kg, state, render_buffer));
+#else
+ ccl_gpu_kernel_call(integrator_shade_surface_raytrace(NULL, state, render_buffer));
+#endif
}
}
ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
- kernel_gpu_integrator_shade_volume(const int *path_index_array,
- float *render_buffer,
- const int work_size)
+ ccl_gpu_kernel_signature(integrator_shade_volume,
+ ccl_global const int *path_index_array,
+ ccl_global float *render_buffer,
+ const int work_size)
{
const int global_index = ccl_gpu_global_id_x();
if (global_index < work_size) {
const int state = (path_index_array) ? path_index_array[global_index] : global_index;
- integrator_shade_volume(NULL, state, render_buffer);
+ ccl_gpu_kernel_call(integrator_shade_volume(NULL, state, render_buffer));
}
}
-extern "C" __global__ void __launch_bounds__(GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE)
- kernel_gpu_integrator_queued_paths_array(int num_states,
- int *indices,
- int *num_indices,
- int kernel)
+ccl_gpu_kernel_threads(GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE)
+ ccl_gpu_kernel_signature(integrator_queued_paths_array,
+ int num_states,
+ ccl_global int *indices,
+ ccl_global int *num_indices,
+ int kernel_index)
{
+ ccl_gpu_kernel_lambda(INTEGRATOR_STATE(state, path, queued_kernel) == kernel_index,
+ int kernel_index);
+ ccl_gpu_kernel_lambda_pass.kernel_index = kernel_index;
+
gpu_parallel_active_index_array<GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE>(
- num_states, indices, num_indices, [kernel](const int state) {
- return (INTEGRATOR_STATE(path, queued_kernel) == kernel);
- });
+ num_states, indices, num_indices, ccl_gpu_kernel_lambda_pass);
}
-extern "C" __global__ void __launch_bounds__(GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE)
- kernel_gpu_integrator_queued_shadow_paths_array(int num_states,
- int *indices,
- int *num_indices,
- int kernel)
+ccl_gpu_kernel_threads(GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE)
+ ccl_gpu_kernel_signature(integrator_queued_shadow_paths_array,
+ int num_states,
+ ccl_global int *indices,
+ ccl_global int *num_indices,
+ int kernel_index)
{
+ ccl_gpu_kernel_lambda(INTEGRATOR_STATE(state, shadow_path, queued_kernel) == kernel_index,
+ int kernel_index);
+ ccl_gpu_kernel_lambda_pass.kernel_index = kernel_index;
+
gpu_parallel_active_index_array<GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE>(
- num_states, indices, num_indices, [kernel](const int state) {
- return (INTEGRATOR_STATE(shadow_path, queued_kernel) == kernel);
- });
+ num_states, indices, num_indices, ccl_gpu_kernel_lambda_pass);
}
-extern "C" __global__ void __launch_bounds__(GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE)
- kernel_gpu_integrator_active_paths_array(int num_states, int *indices, int *num_indices)
+ccl_gpu_kernel_threads(GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE)
+ ccl_gpu_kernel_signature(integrator_active_paths_array,
+ int num_states,
+ ccl_global int *indices,
+ ccl_global int *num_indices)
{
+ ccl_gpu_kernel_lambda(INTEGRATOR_STATE(state, path, queued_kernel) != 0);
+
gpu_parallel_active_index_array<GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE>(
- num_states, indices, num_indices, [](const int state) {
- return (INTEGRATOR_STATE(path, queued_kernel) != 0) ||
- (INTEGRATOR_STATE(shadow_path, queued_kernel) != 0);
- });
+ num_states, indices, num_indices, ccl_gpu_kernel_lambda_pass);
}
-extern "C" __global__ void __launch_bounds__(GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE)
- kernel_gpu_integrator_terminated_paths_array(int num_states,
- int *indices,
- int *num_indices,
- int indices_offset)
+ccl_gpu_kernel_threads(GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE)
+ ccl_gpu_kernel_signature(integrator_terminated_paths_array,
+ int num_states,
+ ccl_global int *indices,
+ ccl_global int *num_indices,
+ int indices_offset)
{
+ ccl_gpu_kernel_lambda(INTEGRATOR_STATE(state, path, queued_kernel) == 0);
+
gpu_parallel_active_index_array<GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE>(
- num_states, indices + indices_offset, num_indices, [](const int state) {
- return (INTEGRATOR_STATE(path, queued_kernel) == 0) &&
- (INTEGRATOR_STATE(shadow_path, queued_kernel) == 0);
- });
+ num_states, indices + indices_offset, num_indices, ccl_gpu_kernel_lambda_pass);
}
-extern "C" __global__ void __launch_bounds__(GPU_PARALLEL_SORTED_INDEX_DEFAULT_BLOCK_SIZE)
- kernel_gpu_integrator_sorted_paths_array(
- int num_states, int *indices, int *num_indices, int *key_prefix_sum, int kernel)
+ccl_gpu_kernel_threads(GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE)
+ ccl_gpu_kernel_signature(integrator_terminated_shadow_paths_array,
+ int num_states,
+ ccl_global int *indices,
+ ccl_global int *num_indices,
+ int indices_offset)
{
- gpu_parallel_sorted_index_array<GPU_PARALLEL_SORTED_INDEX_DEFAULT_BLOCK_SIZE>(
- num_states, indices, num_indices, key_prefix_sum, [kernel](const int state) {
- return (INTEGRATOR_STATE(path, queued_kernel) == kernel) ?
- INTEGRATOR_STATE(path, shader_sort_key) :
- GPU_PARALLEL_SORTED_INDEX_INACTIVE_KEY;
- });
+ ccl_gpu_kernel_lambda(INTEGRATOR_STATE(state, shadow_path, queued_kernel) == 0);
+
+ gpu_parallel_active_index_array<GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE>(
+ num_states, indices + indices_offset, num_indices, ccl_gpu_kernel_lambda_pass);
+}
+
+ccl_gpu_kernel_threads(GPU_PARALLEL_SORTED_INDEX_DEFAULT_BLOCK_SIZE)
+ ccl_gpu_kernel_signature(integrator_sorted_paths_array,
+ int num_states,
+ int num_states_limit,
+ ccl_global int *indices,
+ ccl_global int *num_indices,
+ ccl_global int *key_counter,
+ ccl_global int *key_prefix_sum,
+ int kernel_index)
+{
+ ccl_gpu_kernel_lambda((INTEGRATOR_STATE(state, path, queued_kernel) == kernel_index) ?
+ INTEGRATOR_STATE(state, path, shader_sort_key) :
+ GPU_PARALLEL_SORTED_INDEX_INACTIVE_KEY,
+ int kernel_index);
+ ccl_gpu_kernel_lambda_pass.kernel_index = kernel_index;
+
+ const uint state_index = ccl_gpu_global_id_x();
+ gpu_parallel_sorted_index_array(state_index,
+ num_states,
+ num_states_limit,
+ indices,
+ num_indices,
+ key_counter,
+ key_prefix_sum,
+ ccl_gpu_kernel_lambda_pass);
+}
+
+ccl_gpu_kernel_threads(GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE)
+ ccl_gpu_kernel_signature(integrator_compact_paths_array,
+ int num_states,
+ ccl_global int *indices,
+ ccl_global int *num_indices,
+ int num_active_paths)
+{
+ ccl_gpu_kernel_lambda((state >= num_active_paths) &&
+ (INTEGRATOR_STATE(state, path, queued_kernel) != 0),
+ int num_active_paths);
+ ccl_gpu_kernel_lambda_pass.num_active_paths = num_active_paths;
+
+ gpu_parallel_active_index_array<GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE>(
+ num_states, indices, num_indices, ccl_gpu_kernel_lambda_pass);
+}
+
+ccl_gpu_kernel_threads(GPU_PARALLEL_SORTED_INDEX_DEFAULT_BLOCK_SIZE)
+ ccl_gpu_kernel_signature(integrator_compact_states,
+ ccl_global const int *active_terminated_states,
+ const int active_states_offset,
+ const int terminated_states_offset,
+ const int work_size)
+{
+ const int global_index = ccl_gpu_global_id_x();
+
+ if (global_index < work_size) {
+ const int from_state = active_terminated_states[active_states_offset + global_index];
+ const int to_state = active_terminated_states[terminated_states_offset + global_index];
+
+ ccl_gpu_kernel_call(integrator_state_move(NULL, to_state, from_state));
+ }
}
-extern "C" __global__ void __launch_bounds__(GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE)
- kernel_gpu_integrator_compact_paths_array(int num_states,
- int *indices,
- int *num_indices,
- int num_active_paths)
+ccl_gpu_kernel_threads(GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE)
+ ccl_gpu_kernel_signature(integrator_compact_shadow_paths_array,
+ int num_states,
+ ccl_global int *indices,
+ ccl_global int *num_indices,
+ int num_active_paths)
{
+ ccl_gpu_kernel_lambda((state >= num_active_paths) &&
+ (INTEGRATOR_STATE(state, shadow_path, queued_kernel) != 0),
+ int num_active_paths);
+ ccl_gpu_kernel_lambda_pass.num_active_paths = num_active_paths;
+
gpu_parallel_active_index_array<GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE>(
- num_states, indices, num_indices, [num_active_paths](const int state) {
- return (state >= num_active_paths) &&
- ((INTEGRATOR_STATE(path, queued_kernel) != 0) ||
- (INTEGRATOR_STATE(shadow_path, queued_kernel) != 0));
- });
+ num_states, indices, num_indices, ccl_gpu_kernel_lambda_pass);
}
-extern "C" __global__ void __launch_bounds__(GPU_PARALLEL_SORTED_INDEX_DEFAULT_BLOCK_SIZE)
- kernel_gpu_integrator_compact_states(const int *active_terminated_states,
- const int active_states_offset,
- const int terminated_states_offset,
- const int work_size)
+ccl_gpu_kernel_threads(GPU_PARALLEL_SORTED_INDEX_DEFAULT_BLOCK_SIZE)
+ ccl_gpu_kernel_signature(integrator_compact_shadow_states,
+ ccl_global const int *active_terminated_states,
+ const int active_states_offset,
+ const int terminated_states_offset,
+ const int work_size)
{
const int global_index = ccl_gpu_global_id_x();
@@ -321,14 +441,14 @@ extern "C" __global__ void __launch_bounds__(GPU_PARALLEL_SORTED_INDEX_DEFAULT_B
const int from_state = active_terminated_states[active_states_offset + global_index];
const int to_state = active_terminated_states[terminated_states_offset + global_index];
- integrator_state_move(to_state, from_state);
+ ccl_gpu_kernel_call(integrator_shadow_state_move(NULL, to_state, from_state));
}
}
-extern "C" __global__ void __launch_bounds__(GPU_PARALLEL_PREFIX_SUM_DEFAULT_BLOCK_SIZE)
- kernel_gpu_prefix_sum(int *values, int num_values)
+ccl_gpu_kernel_threads(GPU_PARALLEL_PREFIX_SUM_DEFAULT_BLOCK_SIZE) ccl_gpu_kernel_signature(
+ prefix_sum, ccl_global int *counter, ccl_global int *prefix_sum, int num_values)
{
- gpu_parallel_prefix_sum<GPU_PARALLEL_PREFIX_SUM_DEFAULT_BLOCK_SIZE>(values, num_values);
+ gpu_parallel_prefix_sum(ccl_gpu_global_id_x(), counter, prefix_sum, num_values);
}
/* --------------------------------------------------------------------
@@ -336,16 +456,17 @@ extern "C" __global__ void __launch_bounds__(GPU_PARALLEL_PREFIX_SUM_DEFAULT_BLO
*/
ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
- kernel_gpu_adaptive_sampling_convergence_check(float *render_buffer,
- int sx,
- int sy,
- int sw,
- int sh,
- float threshold,
- bool reset,
- int offset,
- int stride,
- uint *num_active_pixels)
+ ccl_gpu_kernel_signature(adaptive_sampling_convergence_check,
+ ccl_global float *render_buffer,
+ int sx,
+ int sy,
+ int sw,
+ int sh,
+ float threshold,
+ bool reset,
+ int offset,
+ int stride,
+ ccl_global uint *num_active_pixels)
{
const int work_index = ccl_gpu_global_id_x();
const int y = work_index / sw;
@@ -354,37 +475,51 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
bool converged = true;
if (x < sw && y < sh) {
- converged = kernel_adaptive_sampling_convergence_check(
- nullptr, render_buffer, sx + x, sy + y, threshold, reset, offset, stride);
+ converged = ccl_gpu_kernel_call(kernel_adaptive_sampling_convergence_check(
+ nullptr, render_buffer, sx + x, sy + y, threshold, reset, offset, stride));
}
/* NOTE: All threads specified in the mask must execute the intrinsic. */
- const uint num_active_pixels_mask = ccl_gpu_ballot(!converged);
+ const auto num_active_pixels_mask = ccl_gpu_ballot(!converged);
const int lane_id = ccl_gpu_thread_idx_x % ccl_gpu_warp_size;
if (lane_id == 0) {
- atomic_fetch_and_add_uint32(num_active_pixels, __popc(num_active_pixels_mask));
+ atomic_fetch_and_add_uint32(num_active_pixels, popcount(num_active_pixels_mask));
}
}
ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
- kernel_gpu_adaptive_sampling_filter_x(
- float *render_buffer, int sx, int sy, int sw, int sh, int offset, int stride)
+ ccl_gpu_kernel_signature(adaptive_sampling_filter_x,
+ ccl_global float *render_buffer,
+ int sx,
+ int sy,
+ int sw,
+ int sh,
+ int offset,
+ int stride)
{
const int y = ccl_gpu_global_id_x();
if (y < sh) {
- kernel_adaptive_sampling_filter_x(NULL, render_buffer, sy + y, sx, sw, offset, stride);
+ ccl_gpu_kernel_call(
+ kernel_adaptive_sampling_filter_x(NULL, render_buffer, sy + y, sx, sw, offset, stride));
}
}
ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
- kernel_gpu_adaptive_sampling_filter_y(
- float *render_buffer, int sx, int sy, int sw, int sh, int offset, int stride)
+ ccl_gpu_kernel_signature(adaptive_sampling_filter_y,
+ ccl_global float *render_buffer,
+ int sx,
+ int sy,
+ int sw,
+ int sh,
+ int offset,
+ int stride)
{
const int x = ccl_gpu_global_id_x();
if (x < sw) {
- kernel_adaptive_sampling_filter_y(NULL, render_buffer, sx + x, sy, sh, offset, stride);
+ ccl_gpu_kernel_call(
+ kernel_adaptive_sampling_filter_y(NULL, render_buffer, sx + x, sy, sh, offset, stride));
}
}
@@ -393,12 +528,14 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
*/
ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
- kernel_gpu_cryptomatte_postprocess(float *render_buffer, int num_pixels)
+ ccl_gpu_kernel_signature(cryptomatte_postprocess,
+ ccl_global float *render_buffer,
+ int num_pixels)
{
const int pixel_index = ccl_gpu_global_id_x();
if (pixel_index < num_pixels) {
- kernel_cryptomatte_post(nullptr, render_buffer, pixel_index);
+ ccl_gpu_kernel_call(kernel_cryptomatte_post(nullptr, render_buffer, pixel_index));
}
}
@@ -406,202 +543,142 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
* Film.
*/
-/* Common implementation for float destination. */
-template<typename Processor>
-ccl_device_inline void kernel_gpu_film_convert_common(const KernelFilmConvert *kfilm_convert,
- float *pixels,
- float *render_buffer,
- int num_pixels,
- int width,
- int offset,
- int stride,
- int dst_offset,
- int dst_stride,
- const Processor &processor)
-{
- const int render_pixel_index = ccl_gpu_global_id_x();
- if (render_pixel_index >= num_pixels) {
- return;
- }
-
- const uint64_t render_buffer_offset = (uint64_t)render_pixel_index * kfilm_convert->pass_stride;
- ccl_global const float *buffer = render_buffer + render_buffer_offset;
- ccl_global float *pixel = pixels +
- (render_pixel_index + dst_offset) * kfilm_convert->pixel_stride;
-
- processor(kfilm_convert, buffer, pixel);
-}
-
-/* Common implementation for half4 destination and 4-channel input pass. */
-template<typename Processor>
-ccl_device_inline void kernel_gpu_film_convert_half_rgba_common_rgba(
- const KernelFilmConvert *kfilm_convert,
- uchar4 *rgba,
- float *render_buffer,
- int num_pixels,
- int width,
- int offset,
- int stride,
- int rgba_offset,
- int rgba_stride,
- const Processor &processor)
-{
- const int render_pixel_index = ccl_gpu_global_id_x();
- if (render_pixel_index >= num_pixels) {
- return;
- }
-
- const uint64_t render_buffer_offset = (uint64_t)render_pixel_index * kfilm_convert->pass_stride;
- ccl_global const float *buffer = render_buffer + render_buffer_offset;
-
- float pixel[4];
- processor(kfilm_convert, buffer, pixel);
-
- film_apply_pass_pixel_overlays_rgba(kfilm_convert, buffer, pixel);
-
- const int x = render_pixel_index % width;
- const int y = render_pixel_index / width;
-
+ccl_device_inline void kernel_gpu_film_convert_half_write(ccl_global uchar4 *rgba,
+ const int rgba_offset,
+ const int rgba_stride,
+ const int x,
+ const int y,
+ const half4 half_pixel)
+{
+ /* Work around HIP issue with half float display, see T92972. */
+#ifdef __KERNEL_HIP__
+ ccl_global half *out = ((ccl_global half *)rgba) + (rgba_offset + y * rgba_stride + x) * 4;
+ out[0] = half_pixel.x;
+ out[1] = half_pixel.y;
+ out[2] = half_pixel.z;
+ out[3] = half_pixel.w;
+#else
ccl_global half4 *out = ((ccl_global half4 *)rgba) + rgba_offset + y * rgba_stride + x;
- float4_store_half((ccl_global half *)out, make_float4(pixel[0], pixel[1], pixel[2], pixel[3]));
-}
-
-/* Common implementation for half4 destination and 3-channel input pass. */
-template<typename Processor>
-ccl_device_inline void kernel_gpu_film_convert_half_rgba_common_rgb(
- const KernelFilmConvert *kfilm_convert,
- uchar4 *rgba,
- float *render_buffer,
- int num_pixels,
- int width,
- int offset,
- int stride,
- int rgba_offset,
- int rgba_stride,
- const Processor &processor)
-{
- kernel_gpu_film_convert_half_rgba_common_rgba(
- kfilm_convert,
- rgba,
- render_buffer,
- num_pixels,
- width,
- offset,
- stride,
- rgba_offset,
- rgba_stride,
- [&processor](const KernelFilmConvert *kfilm_convert,
- ccl_global const float *buffer,
- float *pixel_rgba) {
- processor(kfilm_convert, buffer, pixel_rgba);
- pixel_rgba[3] = 1.0f;
- });
-}
-
-/* Common implementation for half4 destination and single channel input pass. */
-template<typename Processor>
-ccl_device_inline void kernel_gpu_film_convert_half_rgba_common_value(
- const KernelFilmConvert *kfilm_convert,
- uchar4 *rgba,
- float *render_buffer,
- int num_pixels,
- int width,
- int offset,
- int stride,
- int rgba_offset,
- int rgba_stride,
- const Processor &processor)
-{
- kernel_gpu_film_convert_half_rgba_common_rgba(
- kfilm_convert,
- rgba,
- render_buffer,
- num_pixels,
- width,
- offset,
- stride,
- rgba_offset,
- rgba_stride,
- [&processor](const KernelFilmConvert *kfilm_convert,
- ccl_global const float *buffer,
- float *pixel_rgba) {
- float value;
- processor(kfilm_convert, buffer, &value);
-
- pixel_rgba[0] = value;
- pixel_rgba[1] = value;
- pixel_rgba[2] = value;
- pixel_rgba[3] = 1.0f;
- });
-}
-
-#define KERNEL_FILM_CONVERT_PROC(name) \
- ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) name
-
-#define KERNEL_FILM_CONVERT_DEFINE(variant, channels) \
- KERNEL_FILM_CONVERT_PROC(kernel_gpu_film_convert_##variant) \
- (const KernelFilmConvert kfilm_convert, \
- float *pixels, \
- float *render_buffer, \
- int num_pixels, \
- int width, \
- int offset, \
- int stride, \
- int rgba_offset, \
- int rgba_stride) \
+ *out = half_pixel;
+#endif
+}
+
+#ifdef __KERNEL_METAL__
+
+/* Fetch into a local variable on Metal - there is minimal overhead. Templating the
+ * film_get_pass_pixel_... functions works on MSL, but not on other compilers. */
+# define FILM_GET_PASS_PIXEL_F32(variant, input_channel_count) \
+ float local_pixel[4]; \
+ film_get_pass_pixel_##variant(&kfilm_convert, buffer, local_pixel); \
+ if (input_channel_count >= 1) { \
+ pixel[0] = local_pixel[0]; \
+ } \
+ if (input_channel_count >= 2) { \
+ pixel[1] = local_pixel[1]; \
+ } \
+ if (input_channel_count >= 3) { \
+ pixel[2] = local_pixel[2]; \
+ } \
+ if (input_channel_count >= 4) { \
+ pixel[3] = local_pixel[3]; \
+ }
+
+#else
+
+# define FILM_GET_PASS_PIXEL_F32(variant, input_channel_count) \
+ film_get_pass_pixel_##variant(&kfilm_convert, buffer, pixel);
+
+#endif
+
+#define KERNEL_FILM_CONVERT_VARIANT(variant, input_channel_count) \
+ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) \
+ ccl_gpu_kernel_signature(film_convert_##variant, \
+ const KernelFilmConvert kfilm_convert, \
+ ccl_global float *pixels, \
+ ccl_global float *render_buffer, \
+ int num_pixels, \
+ int width, \
+ int offset, \
+ int stride, \
+ int rgba_offset, \
+ int rgba_stride) \
{ \
- kernel_gpu_film_convert_common(&kfilm_convert, \
- pixels, \
- render_buffer, \
- num_pixels, \
- width, \
- offset, \
- stride, \
- rgba_offset, \
- rgba_stride, \
- film_get_pass_pixel_##variant); \
+ const int render_pixel_index = ccl_gpu_global_id_x(); \
+ if (render_pixel_index >= num_pixels) { \
+ return; \
+ } \
+\
+ const int x = render_pixel_index % width; \
+ const int y = render_pixel_index / width; \
+\
+ ccl_global const float *buffer = render_buffer + offset + x * kfilm_convert.pass_stride + \
+ y * stride * kfilm_convert.pass_stride; \
+\
+ ccl_global float *pixel = pixels + \
+ (render_pixel_index + rgba_offset) * kfilm_convert.pixel_stride; \
+\
+ FILM_GET_PASS_PIXEL_F32(variant, input_channel_count); \
} \
- KERNEL_FILM_CONVERT_PROC(kernel_gpu_film_convert_##variant##_half_rgba) \
- (const KernelFilmConvert kfilm_convert, \
- uchar4 *rgba, \
- float *render_buffer, \
- int num_pixels, \
- int width, \
- int offset, \
- int stride, \
- int rgba_offset, \
- int rgba_stride) \
+\
+ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) \
+ ccl_gpu_kernel_signature(film_convert_##variant##_half_rgba, \
+ const KernelFilmConvert kfilm_convert, \
+ ccl_global uchar4 *rgba, \
+ ccl_global float *render_buffer, \
+ int num_pixels, \
+ int width, \
+ int offset, \
+ int stride, \
+ int rgba_offset, \
+ int rgba_stride) \
{ \
- kernel_gpu_film_convert_half_rgba_common_##channels(&kfilm_convert, \
- rgba, \
- render_buffer, \
- num_pixels, \
- width, \
- offset, \
- stride, \
- rgba_offset, \
- rgba_stride, \
- film_get_pass_pixel_##variant); \
- }
-
-KERNEL_FILM_CONVERT_DEFINE(depth, value)
-KERNEL_FILM_CONVERT_DEFINE(mist, value)
-KERNEL_FILM_CONVERT_DEFINE(sample_count, value)
-KERNEL_FILM_CONVERT_DEFINE(float, value)
-
-KERNEL_FILM_CONVERT_DEFINE(light_path, rgb)
-KERNEL_FILM_CONVERT_DEFINE(float3, rgb)
-
-KERNEL_FILM_CONVERT_DEFINE(motion, rgba)
-KERNEL_FILM_CONVERT_DEFINE(cryptomatte, rgba)
-KERNEL_FILM_CONVERT_DEFINE(shadow_catcher, rgba)
-KERNEL_FILM_CONVERT_DEFINE(shadow_catcher_matte_with_shadow, rgba)
-KERNEL_FILM_CONVERT_DEFINE(combined, rgba)
-KERNEL_FILM_CONVERT_DEFINE(float4, rgba)
-
-#undef KERNEL_FILM_CONVERT_DEFINE
-#undef KERNEL_FILM_CONVERT_HALF_RGBA_DEFINE
-#undef KERNEL_FILM_CONVERT_PROC
+ const int render_pixel_index = ccl_gpu_global_id_x(); \
+ if (render_pixel_index >= num_pixels) { \
+ return; \
+ } \
+\
+ const int x = render_pixel_index % width; \
+ const int y = render_pixel_index / width; \
+\
+ ccl_global const float *buffer = render_buffer + offset + x * kfilm_convert.pass_stride + \
+ y * stride * kfilm_convert.pass_stride; \
+\
+ float pixel[4]; \
+ film_get_pass_pixel_##variant(&kfilm_convert, buffer, pixel); \
+\
+ if (input_channel_count == 1) { \
+ pixel[1] = pixel[2] = pixel[0]; \
+ } \
+ if (input_channel_count <= 3) { \
+ pixel[3] = 1.0f; \
+ } \
+\
+ film_apply_pass_pixel_overlays_rgba(&kfilm_convert, buffer, pixel); \
+\
+ const half4 half_pixel = float4_to_half4_display( \
+ make_float4(pixel[0], pixel[1], pixel[2], pixel[3])); \
+ kernel_gpu_film_convert_half_write(rgba, rgba_offset, rgba_stride, x, y, half_pixel); \
+ }
+
+/* 1 channel inputs */
+KERNEL_FILM_CONVERT_VARIANT(depth, 1)
+KERNEL_FILM_CONVERT_VARIANT(mist, 1)
+KERNEL_FILM_CONVERT_VARIANT(sample_count, 1)
+KERNEL_FILM_CONVERT_VARIANT(float, 1)
+
+/* 3 channel inputs */
+KERNEL_FILM_CONVERT_VARIANT(light_path, 3)
+KERNEL_FILM_CONVERT_VARIANT(float3, 3)
+
+/* 4 channel inputs */
+KERNEL_FILM_CONVERT_VARIANT(motion, 4)
+KERNEL_FILM_CONVERT_VARIANT(cryptomatte, 4)
+KERNEL_FILM_CONVERT_VARIANT(shadow_catcher, 4)
+KERNEL_FILM_CONVERT_VARIANT(shadow_catcher_matte_with_shadow, 4)
+KERNEL_FILM_CONVERT_VARIANT(combined, 4)
+KERNEL_FILM_CONVERT_VARIANT(float4, 4)
+
+#undef KERNEL_FILM_CONVERT_VARIANT
/* --------------------------------------------------------------------
* Shader evaluation.
@@ -610,28 +687,46 @@ KERNEL_FILM_CONVERT_DEFINE(float4, rgba)
/* Displacement */
ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
- kernel_gpu_shader_eval_displace(KernelShaderEvalInput *input,
- float4 *output,
- const int offset,
- const int work_size)
+ ccl_gpu_kernel_signature(shader_eval_displace,
+ ccl_global KernelShaderEvalInput *input,
+ ccl_global float *output,
+ const int offset,
+ const int work_size)
+{
+ int i = ccl_gpu_global_id_x();
+ if (i < work_size) {
+ ccl_gpu_kernel_call(kernel_displace_evaluate(NULL, input, output, offset + i));
+ }
+}
+
+/* Background */
+
+ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
+ ccl_gpu_kernel_signature(shader_eval_background,
+ ccl_global KernelShaderEvalInput *input,
+ ccl_global float *output,
+ const int offset,
+ const int work_size)
{
int i = ccl_gpu_global_id_x();
if (i < work_size) {
- kernel_displace_evaluate(NULL, input, output, offset + i);
+ ccl_gpu_kernel_call(kernel_background_evaluate(NULL, input, output, offset + i));
}
}
-/* Background Shader Evaluation */
+/* Curve Shadow Transparency */
ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
- kernel_gpu_shader_eval_background(KernelShaderEvalInput *input,
- float4 *output,
- const int offset,
- const int work_size)
+ ccl_gpu_kernel_signature(shader_eval_curve_shadow_transparency,
+ ccl_global KernelShaderEvalInput *input,
+ ccl_global float *output,
+ const int offset,
+ const int work_size)
{
int i = ccl_gpu_global_id_x();
if (i < work_size) {
- kernel_background_evaluate(NULL, input, output, offset + i);
+ ccl_gpu_kernel_call(
+ kernel_curve_shadow_transparency_evaluate(NULL, input, output, offset + i));
}
}
@@ -640,15 +735,16 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
*/
ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
- kernel_gpu_filter_color_preprocess(float *render_buffer,
- int full_x,
- int full_y,
- int width,
- int height,
- int offset,
- int stride,
- int pass_stride,
- int pass_denoised)
+ ccl_gpu_kernel_signature(filter_color_preprocess,
+ ccl_global float *render_buffer,
+ int full_x,
+ int full_y,
+ int width,
+ int height,
+ int offset,
+ int stride,
+ int pass_stride,
+ int pass_denoised)
{
const int work_index = ccl_gpu_global_id_x();
const int y = work_index / width;
@@ -659,31 +755,34 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
}
const uint64_t render_pixel_index = offset + (x + full_x) + (y + full_y) * stride;
- float *buffer = render_buffer + render_pixel_index * pass_stride;
+ ccl_global float *buffer = render_buffer + render_pixel_index * pass_stride;
- float *color_out = buffer + pass_denoised;
+ ccl_global float *color_out = buffer + pass_denoised;
color_out[0] = clamp(color_out[0], 0.0f, 10000.0f);
color_out[1] = clamp(color_out[1], 0.0f, 10000.0f);
color_out[2] = clamp(color_out[2], 0.0f, 10000.0f);
}
ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
- kernel_gpu_filter_guiding_preprocess(float *guiding_buffer,
- int guiding_pass_stride,
- int guiding_pass_albedo,
- int guiding_pass_normal,
- const float *render_buffer,
- int render_offset,
- int render_stride,
- int render_pass_stride,
- int render_pass_sample_count,
- int render_pass_denoising_albedo,
- int render_pass_denoising_normal,
- int full_x,
- int full_y,
- int width,
- int height,
- int num_samples)
+ ccl_gpu_kernel_signature(filter_guiding_preprocess,
+ ccl_global float *guiding_buffer,
+ int guiding_pass_stride,
+ int guiding_pass_albedo,
+ int guiding_pass_normal,
+ int guiding_pass_flow,
+ ccl_global const float *render_buffer,
+ int render_offset,
+ int render_stride,
+ int render_pass_stride,
+ int render_pass_sample_count,
+ int render_pass_denoising_albedo,
+ int render_pass_denoising_normal,
+ int render_pass_motion,
+ int full_x,
+ int full_y,
+ int width,
+ int height,
+ int num_samples)
{
const int work_index = ccl_gpu_global_id_x();
const int y = work_index / width;
@@ -694,10 +793,10 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
}
const uint64_t guiding_pixel_index = x + y * width;
- float *guiding_pixel = guiding_buffer + guiding_pixel_index * guiding_pass_stride;
+ ccl_global float *guiding_pixel = guiding_buffer + guiding_pixel_index * guiding_pass_stride;
const uint64_t render_pixel_index = render_offset + (x + full_x) + (y + full_y) * render_stride;
- const float *buffer = render_buffer + render_pixel_index * render_pass_stride;
+ ccl_global const float *buffer = render_buffer + render_pixel_index * render_pass_stride;
float pixel_scale;
if (render_pass_sample_count == PASS_UNUSED) {
@@ -711,8 +810,8 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
if (guiding_pass_albedo != PASS_UNUSED) {
kernel_assert(render_pass_denoising_albedo != PASS_UNUSED);
- const float *aledo_in = buffer + render_pass_denoising_albedo;
- float *albedo_out = guiding_pixel + guiding_pass_albedo;
+ ccl_global const float *aledo_in = buffer + render_pass_denoising_albedo;
+ ccl_global float *albedo_out = guiding_pixel + guiding_pass_albedo;
albedo_out[0] = aledo_in[0] * pixel_scale;
albedo_out[1] = aledo_in[1] * pixel_scale;
@@ -720,24 +819,36 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
}
/* Normal pass. */
- if (render_pass_denoising_normal != PASS_UNUSED) {
+ if (guiding_pass_normal != PASS_UNUSED) {
kernel_assert(render_pass_denoising_normal != PASS_UNUSED);
- const float *normal_in = buffer + render_pass_denoising_normal;
- float *normal_out = guiding_pixel + guiding_pass_normal;
+ ccl_global const float *normal_in = buffer + render_pass_denoising_normal;
+ ccl_global float *normal_out = guiding_pixel + guiding_pass_normal;
normal_out[0] = normal_in[0] * pixel_scale;
normal_out[1] = normal_in[1] * pixel_scale;
normal_out[2] = normal_in[2] * pixel_scale;
}
+
+ /* Flow pass. */
+ if (guiding_pass_flow != PASS_UNUSED) {
+ kernel_assert(render_pass_motion != PASS_UNUSED);
+
+ ccl_global const float *motion_in = buffer + render_pass_motion;
+ ccl_global float *flow_out = guiding_pixel + guiding_pass_flow;
+
+ flow_out[0] = -motion_in[0] * pixel_scale;
+ flow_out[1] = -motion_in[1] * pixel_scale;
+ }
}
ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
- kernel_gpu_filter_guiding_set_fake_albedo(float *guiding_buffer,
- int guiding_pass_stride,
- int guiding_pass_albedo,
- int width,
- int height)
+ ccl_gpu_kernel_signature(filter_guiding_set_fake_albedo,
+ ccl_global float *guiding_buffer,
+ int guiding_pass_stride,
+ int guiding_pass_albedo,
+ int width,
+ int height)
{
kernel_assert(guiding_pass_albedo != PASS_UNUSED);
@@ -750,9 +861,9 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
}
const uint64_t guiding_pixel_index = x + y * width;
- float *guiding_pixel = guiding_buffer + guiding_pixel_index * guiding_pass_stride;
+ ccl_global float *guiding_pixel = guiding_buffer + guiding_pixel_index * guiding_pass_stride;
- float *albedo_out = guiding_pixel + guiding_pass_albedo;
+ ccl_global float *albedo_out = guiding_pixel + guiding_pass_albedo;
albedo_out[0] = 0.5f;
albedo_out[1] = 0.5f;
@@ -760,20 +871,21 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
}
ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
- kernel_gpu_filter_color_postprocess(float *render_buffer,
- int full_x,
- int full_y,
- int width,
- int height,
- int offset,
- int stride,
- int pass_stride,
- int num_samples,
- int pass_noisy,
- int pass_denoised,
- int pass_sample_count,
- int num_components,
- bool use_compositing)
+ ccl_gpu_kernel_signature(filter_color_postprocess,
+ ccl_global float *render_buffer,
+ int full_x,
+ int full_y,
+ int width,
+ int height,
+ int offset,
+ int stride,
+ int pass_stride,
+ int num_samples,
+ int pass_noisy,
+ int pass_denoised,
+ int pass_sample_count,
+ int num_components,
+ bool use_compositing)
{
const int work_index = ccl_gpu_global_id_x();
const int y = work_index / width;
@@ -784,7 +896,7 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
}
const uint64_t render_pixel_index = offset + (x + full_x) + (y + full_y) * stride;
- float *buffer = render_buffer + render_pixel_index * pass_stride;
+ ccl_global float *buffer = render_buffer + render_pixel_index * pass_stride;
float pixel_scale;
if (pass_sample_count == PASS_UNUSED) {
@@ -794,7 +906,7 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
pixel_scale = __float_as_uint(buffer[pass_sample_count]);
}
- float *denoised_pixel = buffer + pass_denoised;
+ ccl_global float *denoised_pixel = buffer + pass_denoised;
denoised_pixel[0] *= pixel_scale;
denoised_pixel[1] *= pixel_scale;
@@ -807,13 +919,12 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
/* Currently compositing passes are either 3-component (derived by dividing light passes)
* or do not have transparency (shadow catcher). Implicitly rely on this logic, as it
* simplifies logic and avoids extra memory allocation. */
- const float *noisy_pixel = buffer + pass_noisy;
+ ccl_global const float *noisy_pixel = buffer + pass_noisy;
denoised_pixel[3] = noisy_pixel[3];
}
else {
/* Assigning to zero since this is a default alpha value for 3-component passes, and it
* is an opaque pixel for 4 component passes. */
-
denoised_pixel[3] = 0;
}
}
@@ -823,21 +934,22 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
*/
ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
- kernel_gpu_integrator_shadow_catcher_count_possible_splits(int num_states,
- uint *num_possible_splits)
+ ccl_gpu_kernel_signature(integrator_shadow_catcher_count_possible_splits,
+ int num_states,
+ ccl_global uint *num_possible_splits)
{
const int state = ccl_gpu_global_id_x();
bool can_split = false;
if (state < num_states) {
- can_split = kernel_shadow_catcher_path_can_split(nullptr, state);
+ can_split = ccl_gpu_kernel_call(kernel_shadow_catcher_path_can_split(nullptr, state));
}
/* NOTE: All threads specified in the mask must execute the intrinsic. */
- const uint can_split_mask = ccl_gpu_ballot(can_split);
+ const auto can_split_mask = ccl_gpu_ballot(can_split);
const int lane_id = ccl_gpu_thread_idx_x % ccl_gpu_warp_size;
if (lane_id == 0) {
- atomic_fetch_and_add_uint32(num_possible_splits, __popc(can_split_mask));
+ atomic_fetch_and_add_uint32(num_possible_splits, popcount(can_split_mask));
}
}
diff --git a/intern/cycles/kernel/device/gpu/parallel_active_index.h b/intern/cycles/kernel/device/gpu/parallel_active_index.h
index db4a4bf71e0..a5320edcb3c 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
@@ -31,10 +31,43 @@ CCL_NAMESPACE_BEGIN
# define GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE 512
#endif
+#ifdef __KERNEL_METAL__
+struct ActiveIndexContext {
+ ActiveIndexContext(int _thread_index,
+ int _global_index,
+ int _threadgroup_size,
+ int _simdgroup_size,
+ int _simd_lane_index,
+ int _simd_group_index,
+ int _num_simd_groups,
+ threadgroup int *_simdgroup_offset)
+ : thread_index(_thread_index),
+ global_index(_global_index),
+ blocksize(_threadgroup_size),
+ ccl_gpu_warp_size(_simdgroup_size),
+ thread_warp(_simd_lane_index),
+ warp_index(_simd_group_index),
+ num_warps(_num_simd_groups),
+ warp_offset(_simdgroup_offset)
+ {
+ }
+
+ const int thread_index, global_index, blocksize, ccl_gpu_warp_size, thread_warp, warp_index,
+ num_warps;
+ threadgroup int *warp_offset;
+
+ template<uint blocksizeDummy, typename IsActiveOp>
+ void active_index_array(const uint num_states,
+ ccl_global int *indices,
+ ccl_global int *num_indices,
+ IsActiveOp is_active_op)
+ {
+ const uint state_index = global_index;
+#else
template<uint blocksize, typename IsActiveOp>
__device__ void gpu_parallel_active_index_array(const uint num_states,
- int *indices,
- int *num_indices,
+ ccl_global int *indices,
+ ccl_global int *num_indices,
IsActiveOp is_active_op)
{
extern ccl_gpu_shared int warp_offset[];
@@ -45,43 +78,62 @@ __device__ void gpu_parallel_active_index_array(const uint num_states,
const uint warp_index = thread_index / ccl_gpu_warp_size;
const uint num_warps = blocksize / ccl_gpu_warp_size;
- /* Test if state corresponding to this thread is active. */
const uint state_index = ccl_gpu_block_idx_x * blocksize + thread_index;
- const uint is_active = (state_index < num_states) ? is_active_op(state_index) : 0;
+#endif
- /* For each thread within a warp compute how many other active states precede it. */
- const uint thread_mask = 0xFFFFFFFF >> (ccl_gpu_warp_size - thread_warp);
- const uint thread_offset = ccl_gpu_popc(ccl_gpu_ballot(is_active) & thread_mask);
+ /* Test if state corresponding to this thread is active. */
+ const uint is_active = (state_index < num_states) ? is_active_op(state_index) : 0;
- /* Last thread in warp stores number of active states for each warp. */
- if (thread_warp == ccl_gpu_warp_size - 1) {
- warp_offset[warp_index] = thread_offset + is_active;
- }
+ /* For each thread within a warp compute how many other active states precede it. */
+ const uint thread_offset = popcount(ccl_gpu_ballot(is_active) &
+ ccl_gpu_thread_mask(thread_warp));
- ccl_gpu_syncthreads();
-
- /* Last thread in block converts per-warp sizes to offsets, increments global size of
- * index array and gets offset to write to. */
- if (thread_index == blocksize - 1) {
- /* TODO: parallelize this. */
- int offset = 0;
- for (int i = 0; i < num_warps; i++) {
- int num_active = warp_offset[i];
- warp_offset[i] = offset;
- offset += num_active;
+ /* Last thread in warp stores number of active states for each warp. */
+ if (thread_warp == ccl_gpu_warp_size - 1) {
+ warp_offset[warp_index] = thread_offset + is_active;
}
- const uint block_num_active = warp_offset[warp_index] + thread_offset + is_active;
- warp_offset[num_warps] = atomic_fetch_and_add_uint32(num_indices, block_num_active);
- }
+ ccl_gpu_syncthreads();
+
+ /* Last thread in block converts per-warp sizes to offsets, increments global size of
+ * index array and gets offset to write to. */
+ if (thread_index == blocksize - 1) {
+ /* TODO: parallelize this. */
+ int offset = 0;
+ for (int i = 0; i < num_warps; i++) {
+ int num_active = warp_offset[i];
+ warp_offset[i] = offset;
+ offset += num_active;
+ }
+
+ const uint block_num_active = warp_offset[warp_index] + thread_offset + is_active;
+ warp_offset[num_warps] = atomic_fetch_and_add_uint32(num_indices, block_num_active);
+ }
- ccl_gpu_syncthreads();
+ ccl_gpu_syncthreads();
- /* Write to index array. */
- if (is_active) {
- const uint block_offset = warp_offset[num_warps];
- indices[block_offset + warp_offset[warp_index] + thread_offset] = state_index;
+ /* Write to index array. */
+ if (is_active) {
+ const uint block_offset = warp_offset[num_warps];
+ indices[block_offset + warp_offset[warp_index] + thread_offset] = state_index;
+ }
}
-}
+
+#ifdef __KERNEL_METAL__
+}; /* end class ActiveIndexContext */
+
+/* inject the required thread params into a struct, and redirect to its templated member function
+ */
+# define gpu_parallel_active_index_array \
+ ActiveIndexContext(metal_local_id, \
+ metal_global_id, \
+ metal_local_size, \
+ simdgroup_size, \
+ simd_lane_index, \
+ simd_group_index, \
+ num_simd_groups, \
+ simdgroup_offset) \
+ .active_index_array
+#endif
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/device/gpu/parallel_prefix_sum.h b/intern/cycles/kernel/device/gpu/parallel_prefix_sum.h
index a1349e82efb..4bd002c27e4 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
@@ -33,16 +33,20 @@ CCL_NAMESPACE_BEGIN
# define GPU_PARALLEL_PREFIX_SUM_DEFAULT_BLOCK_SIZE 512
#endif
-template<uint blocksize> __device__ void gpu_parallel_prefix_sum(int *values, const int num_values)
+__device__ void gpu_parallel_prefix_sum(const int global_id,
+ ccl_global int *counter,
+ ccl_global int *prefix_sum,
+ const int num_values)
{
- if (!(ccl_gpu_block_idx_x == 0 && ccl_gpu_thread_idx_x == 0)) {
+ if (global_id != 0) {
return;
}
int offset = 0;
for (int i = 0; i < num_values; i++) {
- const int new_offset = offset + values[i];
- values[i] = offset;
+ const int new_offset = offset + counter[i];
+ prefix_sum[i] = offset;
+ counter[i] = 0;
offset = new_offset;
}
}
diff --git a/intern/cycles/kernel/device/gpu/parallel_sorted_index.h b/intern/cycles/kernel/device/gpu/parallel_sorted_index.h
index 9bca1fad22f..c092e2a21ee 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
@@ -33,20 +33,30 @@ CCL_NAMESPACE_BEGIN
#endif
#define GPU_PARALLEL_SORTED_INDEX_INACTIVE_KEY (~0)
-template<uint blocksize, typename GetKeyOp>
-__device__ void gpu_parallel_sorted_index_array(const uint num_states,
- int *indices,
- int *num_indices,
- int *key_prefix_sum,
+template<typename GetKeyOp>
+__device__ void gpu_parallel_sorted_index_array(const uint state_index,
+ const uint num_states,
+ const int num_states_limit,
+ ccl_global int *indices,
+ ccl_global int *num_indices,
+ ccl_global int *key_counter,
+ ccl_global int *key_prefix_sum,
GetKeyOp get_key_op)
{
- const uint state_index = ccl_gpu_block_idx_x * blocksize + ccl_gpu_thread_idx_x;
const int key = (state_index < num_states) ? get_key_op(state_index) :
GPU_PARALLEL_SORTED_INDEX_INACTIVE_KEY;
if (key != GPU_PARALLEL_SORTED_INDEX_INACTIVE_KEY) {
const uint index = atomic_fetch_and_add_uint32(&key_prefix_sum[key], 1);
- indices[index] = state_index;
+ if (index < num_states_limit) {
+ /* Assign state index. */
+ indices[index] = state_index;
+ }
+ else {
+ /* Can't process this state now, increase the counter again so that
+ * it will be handled in another iteration. */
+ atomic_fetch_and_add_uint32(&key_counter[key], 1);
+ }
}
}
diff --git a/intern/cycles/kernel/device/gpu/work_stealing.h b/intern/cycles/kernel/device/gpu/work_stealing.h
new file mode 100644
index 00000000000..c3083948057
--- /dev/null
+++ b/intern/cycles/kernel/device/gpu/work_stealing.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
+
+/*
+ * Utility functions for work stealing
+ */
+
+/* Map global work index to tile, pixel X/Y and sample. */
+ccl_device_inline void get_work_pixel(ccl_global const KernelWorkTile *tile,
+ uint global_work_index,
+ ccl_private uint *x,
+ ccl_private uint *y,
+ ccl_private uint *sample)
+{
+ uint sample_offset, pixel_offset;
+
+ if (kernel_data.integrator.scrambling_distance < 0.9f) {
+ /* Keep threads for the same sample together. */
+ uint tile_pixels = tile->w * tile->h;
+ sample_offset = global_work_index / tile_pixels;
+ pixel_offset = global_work_index - sample_offset * tile_pixels;
+ }
+ else {
+ /* Keeping threads for the same pixel together.
+ * Appears to improve performance by a few % on CUDA and OptiX. */
+ sample_offset = global_work_index % tile->num_samples;
+ pixel_offset = global_work_index / tile->num_samples;
+ }
+
+ uint y_offset = pixel_offset / tile->w;
+ uint x_offset = pixel_offset - y_offset * tile->w;
+
+ *x = tile->x + x_offset;
+ *y = tile->y + y_offset;
+ *sample = tile->start_sample + sample_offset;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/device/hip/compat.h b/intern/cycles/kernel/device/hip/compat.h
index 95338fe7d6e..fff7a09e884 100644
--- a/intern/cycles/kernel/device/hip/compat.h
+++ b/intern/cycles/kernel/device/hip/compat.h
@@ -45,14 +45,14 @@ typedef unsigned long long uint64_t;
#define ccl_device_forceinline __device__ __forceinline__
#define ccl_device_noinline __device__ __noinline__
#define ccl_device_noinline_cpu ccl_device
+#define ccl_device_inline_method ccl_device
#define ccl_global
-#define ccl_static_constant __constant__
+#define ccl_inline_constant __constant__
#define ccl_device_constant __constant__ __device__
#define ccl_constant const
#define ccl_gpu_shared __shared__
#define ccl_private
#define ccl_may_alias
-#define ccl_addr_space
#define ccl_restrict __restrict__
#define ccl_loop_no_unroll
#define ccl_align(n) __align__(n)
@@ -75,6 +75,7 @@ typedef unsigned long long uint64_t;
#define ccl_gpu_block_idx_x (blockIdx.x)
#define ccl_gpu_grid_dim_x (gridDim.x)
#define ccl_gpu_warp_size (warpSize)
+#define ccl_gpu_thread_mask(thread_warp) uint(0xFFFFFFFF >> (ccl_gpu_warp_size - thread_warp))
#define ccl_gpu_global_id_x() (ccl_gpu_block_idx_x * ccl_gpu_block_dim_x + ccl_gpu_thread_idx_x)
#define ccl_gpu_global_size_x() (ccl_gpu_grid_dim_x * ccl_gpu_block_dim_x)
@@ -84,7 +85,6 @@ typedef unsigned long long uint64_t;
#define ccl_gpu_syncthreads() __syncthreads()
#define ccl_gpu_ballot(predicate) __ballot(predicate)
#define ccl_gpu_shfl_down_sync(mask, var, detla) __shfl_down(var, detla)
-#define ccl_gpu_popc(x) __popc(x)
/* GPU texture objects */
typedef hipTextureObject_t ccl_gpu_tex_object;
@@ -117,5 +117,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/config.h b/intern/cycles/kernel/device/hip/config.h
index 2fde0d46015..7ec744d8ad2 100644
--- a/intern/cycles/kernel/device/hip/config.h
+++ b/intern/cycles/kernel/device/hip/config.h
@@ -35,12 +35,29 @@
/* Compute number of threads per block and minimum blocks per multiprocessor
* given the maximum number of registers per thread. */
-
#define ccl_gpu_kernel(block_num_threads, thread_num_registers) \
extern "C" __global__ void __launch_bounds__(block_num_threads, \
GPU_MULTIPRESSOR_MAX_REGISTERS / \
(block_num_threads * thread_num_registers))
+#define ccl_gpu_kernel_threads(block_num_threads) \
+ extern "C" __global__ void __launch_bounds__(block_num_threads)
+
+#define ccl_gpu_kernel_signature(name, ...) kernel_gpu_##name(__VA_ARGS__)
+
+#define ccl_gpu_kernel_call(x) x
+
+/* Define a function object where "func" is the lambda body, and additional parameters are used to
+ * specify captured state */
+#define ccl_gpu_kernel_lambda(func, ...) \
+ struct KernelLambda { \
+ __VA_ARGS__; \
+ __device__ int operator()(const int state) \
+ { \
+ return (func); \
+ } \
+ } ccl_gpu_kernel_lambda_pass
+
/* sanity checks */
#if GPU_KERNEL_BLOCK_NUM_THREADS > GPU_BLOCK_MAX_THREADS
diff --git a/intern/cycles/kernel/device/hip/globals.h b/intern/cycles/kernel/device/hip/globals.h
index 39978ae7899..d9a560d668b 100644
--- a/intern/cycles/kernel/device/hip/globals.h
+++ b/intern/cycles/kernel/device/hip/globals.h
@@ -18,24 +18,25 @@
#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
/* Not actually used, just a NULL pointer that gets passed everywhere, which we
* hope gets optimized out by the compiler. */
-struct KernelGlobals {
- /* NOTE: Keep the size in sync with SHADOW_STACK_MAX_HITS. */
+struct KernelGlobalsGPU {
int unused[1];
};
+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/metal/compat.h b/intern/cycles/kernel/device/metal/compat.h
new file mode 100644
index 00000000000..1222b68f0ee
--- /dev/null
+++ b/intern/cycles/kernel/device/metal/compat.h
@@ -0,0 +1,316 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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
+
+#define __KERNEL_GPU__
+#define __KERNEL_METAL__
+#define CCL_NAMESPACE_BEGIN
+#define CCL_NAMESPACE_END
+
+#ifndef ATTR_FALLTHROUGH
+# define ATTR_FALLTHROUGH
+#endif
+
+#include <metal_atomic>
+#include <metal_pack>
+#include <metal_stdlib>
+#include <simd/simd.h>
+
+using namespace metal;
+
+#ifdef __METALRT__
+using namespace metal::raytracing;
+#endif
+
+#pragma clang diagnostic ignored "-Wunused-variable"
+#pragma clang diagnostic ignored "-Wsign-compare"
+#pragma clang diagnostic ignored "-Wuninitialized"
+
+/* Qualifiers */
+
+#define ccl_device
+#define ccl_device_inline ccl_device
+#define ccl_device_forceinline ccl_device
+#define ccl_device_noinline ccl_device __attribute__((noinline))
+#define ccl_device_noinline_cpu ccl_device
+#define ccl_device_inline_method ccl_device
+#define ccl_global device
+#define ccl_inline_constant static constant constexpr
+#define ccl_device_constant constant
+#define ccl_constant constant
+#define ccl_gpu_shared threadgroup
+#define ccl_private thread
+#define ccl_may_alias
+#define ccl_restrict __restrict
+#define ccl_loop_no_unroll
+#define ccl_align(n) alignas(n)
+#define ccl_optional_struct_init
+
+/* No assert supported for Metal */
+
+#define kernel_assert(cond)
+
+#define ccl_gpu_global_id_x() metal_global_id
+#define ccl_gpu_warp_size simdgroup_size
+#define ccl_gpu_thread_idx_x simd_group_index
+#define ccl_gpu_thread_mask(thread_warp) uint64_t((1ull << thread_warp) - 1)
+
+#define ccl_gpu_ballot(predicate) ((uint64_t)((simd_vote::vote_t)simd_ballot(predicate)))
+#define ccl_gpu_syncthreads() threadgroup_barrier(mem_flags::mem_threadgroup);
+
+// clang-format off
+
+/* kernel.h adapters */
+
+#define ccl_gpu_kernel(block_num_threads, thread_num_registers)
+#define ccl_gpu_kernel_threads(block_num_threads)
+
+/* Convert a comma-separated list into a semicolon-separated list
+ * (so that we can generate a struct based on kernel entry-point parameters). */
+#define FN0()
+#define FN1(p1) p1;
+#define FN2(p1, p2) p1; p2;
+#define FN3(p1, p2, p3) p1; p2; p3;
+#define FN4(p1, p2, p3, p4) p1; p2; p3; p4;
+#define FN5(p1, p2, p3, p4, p5) p1; p2; p3; p4; p5;
+#define FN6(p1, p2, p3, p4, p5, p6) p1; p2; p3; p4; p5; p6;
+#define FN7(p1, p2, p3, p4, p5, p6, p7) p1; p2; p3; p4; p5; p6; p7;
+#define FN8(p1, p2, p3, p4, p5, p6, p7, p8) p1; p2; p3; p4; p5; p6; p7; p8;
+#define FN9(p1, p2, p3, p4, p5, p6, p7, p8, p9) p1; p2; p3; p4; p5; p6; p7; p8; p9;
+#define FN10(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10) p1; p2; p3; p4; p5; p6; p7; p8; p9; p10;
+#define FN11(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11) p1; p2; p3; p4; p5; p6; p7; p8; p9; p10; p11;
+#define FN12(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12) p1; p2; p3; p4; p5; p6; p7; p8; p9; p10; p11; p12;
+#define FN13(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13) p1; p2; p3; p4; p5; p6; p7; p8; p9; p10; p11; p12; p13;
+#define FN14(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14) p1; p2; p3; p4; p5; p6; p7; p8; p9; p10; p11; p12; p13; p14;
+#define FN15(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15) p1; p2; p3; p4; p5; p6; p7; p8; p9; p10; p11; p12; p13; p14; p15;
+#define FN16(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16) p1; p2; p3; p4; p5; p6; p7; p8; p9; p10; p11; p12; p13; p14; p15; p16;
+#define FN17(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17) p1; p2; p3; p4; p5; p6; p7; p8; p9; p10; p11; p12; p13; p14; p15; p16; p17;
+#define FN18(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18) p1; p2; p3; p4; p5; p6; p7; p8; p9; p10; p11; p12; p13; p14; p15; p16; p17; p18;
+#define FN19(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19) p1; p2; p3; p4; p5; p6; p7; p8; p9; p10; p11; p12; p13; p14; p15; p16; p17; p18; p19;
+#define FN20(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20) p1; p2; p3; p4; p5; p6; p7; p8; p9; p10; p11; p12; p13; p14; p15; p16; p17; p18; p19; p20;
+#define GET_LAST_ARG(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, ...) p20
+#define PARAMS_MAKER(...) GET_LAST_ARG(__VA_ARGS__, FN20, FN19, FN18, FN17, FN16, FN15, FN14, FN13, FN12, FN11, FN10, FN9, FN8, FN7, FN6, FN5, FN4, FN3, FN2, FN1, FN0)
+
+/* Generate a struct containing the entry-point parameters and a "run"
+ * method which can access them implicitly via this-> */
+#define ccl_gpu_kernel_signature(name, ...) \
+struct kernel_gpu_##name \
+{ \
+ PARAMS_MAKER(__VA_ARGS__)(__VA_ARGS__) \
+ void run(thread MetalKernelContext& context, \
+ threadgroup int *simdgroup_offset, \
+ const uint metal_global_id, \
+ const ushort metal_local_id, \
+ const ushort metal_local_size, \
+ uint simdgroup_size, \
+ uint simd_lane_index, \
+ uint simd_group_index, \
+ uint num_simd_groups) ccl_global const; \
+}; \
+kernel void cycles_metal_##name(device const kernel_gpu_##name *params_struct, \
+ constant KernelParamsMetal &ccl_restrict _launch_params_metal, \
+ constant MetalAncillaries *_metal_ancillaries, \
+ threadgroup int *simdgroup_offset[[ threadgroup(0) ]], \
+ const uint metal_global_id [[thread_position_in_grid]], \
+ const ushort metal_local_id [[thread_position_in_threadgroup]], \
+ const ushort metal_local_size [[threads_per_threadgroup]], \
+ uint simdgroup_size [[threads_per_simdgroup]], \
+ uint simd_lane_index [[thread_index_in_simdgroup]], \
+ uint simd_group_index [[simdgroup_index_in_threadgroup]], \
+ uint num_simd_groups [[simdgroups_per_threadgroup]]) { \
+ MetalKernelContext context(_launch_params_metal, _metal_ancillaries); \
+ params_struct->run(context, simdgroup_offset, metal_global_id, metal_local_id, metal_local_size, simdgroup_size, simd_lane_index, simd_group_index, num_simd_groups); \
+} \
+void kernel_gpu_##name::run(thread MetalKernelContext& context, \
+ threadgroup int *simdgroup_offset, \
+ const uint metal_global_id, \
+ const ushort metal_local_id, \
+ const ushort metal_local_size, \
+ uint simdgroup_size, \
+ uint simd_lane_index, \
+ uint simd_group_index, \
+ uint num_simd_groups) ccl_global const
+
+#define ccl_gpu_kernel_call(x) context.x
+
+/* define a function object where "func" is the lambda body, and additional parameters are used to specify captured state */
+#define ccl_gpu_kernel_lambda(func, ...) \
+ struct KernelLambda \
+ { \
+ KernelLambda(ccl_private MetalKernelContext &_context) : context(_context) {} \
+ ccl_private MetalKernelContext &context; \
+ __VA_ARGS__; \
+ int operator()(const int state) const { return (func); } \
+ } ccl_gpu_kernel_lambda_pass(context)
+
+// clang-format on
+
+/* volumetric lambda functions - use function objects for lambda-like functionality */
+#define VOLUME_READ_LAMBDA(function_call) \
+ struct FnObjectRead { \
+ KernelGlobals kg; \
+ ccl_private MetalKernelContext *context; \
+ int state; \
+\
+ VolumeStack operator()(const int i) const \
+ { \
+ return context->function_call; \
+ } \
+ } volume_read_lambda_pass{kg, this, state};
+
+#define VOLUME_WRITE_LAMBDA(function_call) \
+ struct FnObjectWrite { \
+ KernelGlobals kg; \
+ ccl_private MetalKernelContext *context; \
+ int state; \
+\
+ void operator()(const int i, VolumeStack entry) const \
+ { \
+ context->function_call; \
+ } \
+ } volume_write_lambda_pass{kg, this, state};
+
+/* make_type definitions with Metal style element initializers */
+#ifdef make_float2
+# undef make_float2
+#endif
+#ifdef make_float3
+# undef make_float3
+#endif
+#ifdef make_float4
+# undef make_float4
+#endif
+#ifdef make_int2
+# undef make_int2
+#endif
+#ifdef make_int3
+# undef make_int3
+#endif
+#ifdef make_int4
+# undef make_int4
+#endif
+#ifdef make_uchar4
+# undef make_uchar4
+#endif
+
+#define make_float2(x, y) float2(x, y)
+#define make_float3(x, y, z) float3(x, y, z)
+#define make_float4(x, y, z, w) float4(x, y, z, w)
+#define make_int2(x, y) int2(x, y)
+#define make_int3(x, y, z) int3(x, y, z)
+#define make_int4(x, y, z, w) int4(x, y, z, w)
+#define make_uchar4(x, y, z, w) uchar4(x, y, z, w)
+
+/* Math functions */
+
+#define __uint_as_float(x) as_type<float>(x)
+#define __float_as_uint(x) as_type<uint>(x)
+#define __int_as_float(x) as_type<float>(x)
+#define __float_as_int(x) as_type<int>(x)
+#define __float2half(x) half(x)
+#define powf(x, y) pow(float(x), float(y))
+#define fabsf(x) fabs(float(x))
+#define copysignf(x, y) copysign(float(x), float(y))
+#define asinf(x) asin(float(x))
+#define acosf(x) acos(float(x))
+#define atanf(x) atan(float(x))
+#define floorf(x) floor(float(x))
+#define ceilf(x) ceil(float(x))
+#define hypotf(x, y) hypot(float(x), float(y))
+#define atan2f(x, y) atan2(float(x), float(y))
+#define fmaxf(x, y) fmax(float(x), float(y))
+#define fminf(x, y) fmin(float(x), float(y))
+#define fmodf(x, y) fmod(float(x), float(y))
+#define sinhf(x) sinh(float(x))
+#define coshf(x) cosh(float(x))
+#define tanhf(x) tanh(float(x))
+#define saturatef(x) saturate(float(x))
+
+/* Use native functions with possibly lower precision for performance,
+ * no issues found so far. */
+#define trigmode fast
+#define sinf(x) trigmode::sin(float(x))
+#define cosf(x) trigmode::cos(float(x))
+#define tanf(x) trigmode::tan(float(x))
+#define expf(x) trigmode::exp(float(x))
+#define sqrtf(x) trigmode::sqrt(float(x))
+#define logf(x) trigmode::log(float(x))
+
+#define NULL 0
+
+#define __device__
+
+#ifdef __METALRT__
+
+# define __KERNEL_GPU_RAYTRACING__
+
+# if defined(__METALRT_MOTION__)
+# define METALRT_TAGS instancing, instance_motion, primitive_motion
+# else
+# define METALRT_TAGS instancing
+# endif /* __METALRT_MOTION__ */
+
+typedef acceleration_structure<METALRT_TAGS> metalrt_as_type;
+typedef intersection_function_table<triangle_data, METALRT_TAGS> metalrt_ift_type;
+typedef metal::raytracing::intersector<triangle_data, METALRT_TAGS> metalrt_intersector_type;
+
+#endif /* __METALRT__ */
+
+/* texture bindings and sampler setup */
+
+struct Texture2DParamsMetal {
+ texture2d<float, access::sample> tex;
+};
+struct Texture3DParamsMetal {
+ texture3d<float, access::sample> tex;
+};
+
+struct MetalAncillaries {
+ device Texture2DParamsMetal *textures_2d;
+ device Texture3DParamsMetal *textures_3d;
+
+#ifdef __METALRT__
+ metalrt_as_type accel_struct;
+ metalrt_ift_type ift_default;
+ metalrt_ift_type ift_shadow;
+ metalrt_ift_type ift_local;
+#endif
+};
+
+#include "util/half.h"
+#include "util/types.h"
+
+enum SamplerType {
+ SamplerFilterNearest_AddressRepeat,
+ SamplerFilterNearest_AddressClampEdge,
+ SamplerFilterNearest_AddressClampZero,
+
+ SamplerFilterLinear_AddressRepeat,
+ SamplerFilterLinear_AddressClampEdge,
+ SamplerFilterLinear_AddressClampZero,
+
+ SamplerCount
+};
+
+constant constexpr array<sampler, SamplerCount> metal_samplers = {
+ sampler(address::repeat, filter::nearest),
+ sampler(address::clamp_to_edge, filter::nearest),
+ sampler(address::clamp_to_zero, filter::nearest),
+ sampler(address::repeat, filter::linear),
+ sampler(address::clamp_to_edge, filter::linear),
+ sampler(address::clamp_to_zero, filter::linear),
+};
diff --git a/intern/cycles/kernel/device/metal/context_begin.h b/intern/cycles/kernel/device/metal/context_begin.h
new file mode 100644
index 00000000000..2eefd795aa1
--- /dev/null
+++ b/intern/cycles/kernel/device/metal/context_begin.h
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+
+// clang-format off
+
+/* Open the Metal kernel context class
+ * Necessary to access resource bindings */
+class MetalKernelContext {
+ public:
+ constant KernelParamsMetal &launch_params_metal;
+ constant MetalAncillaries *metal_ancillaries;
+
+ MetalKernelContext(constant KernelParamsMetal &_launch_params_metal, constant MetalAncillaries * _metal_ancillaries)
+ : launch_params_metal(_launch_params_metal), metal_ancillaries(_metal_ancillaries)
+ {}
+
+ MetalKernelContext(constant KernelParamsMetal &_launch_params_metal)
+ : launch_params_metal(_launch_params_metal)
+ {}
+
+ /* texture fetch adapter functions */
+ typedef uint64_t ccl_gpu_tex_object;
+
+ template<typename T>
+ inline __attribute__((__always_inline__))
+ T ccl_gpu_tex_object_read_2D(ccl_gpu_tex_object tex, float x, float y) const {
+ kernel_assert(0);
+ return 0;
+ }
+ template<typename T>
+ inline __attribute__((__always_inline__))
+ T ccl_gpu_tex_object_read_3D(ccl_gpu_tex_object tex, float x, float y, float z) const {
+ kernel_assert(0);
+ return 0;
+ }
+
+ // texture2d
+ template<>
+ inline __attribute__((__always_inline__))
+ float4 ccl_gpu_tex_object_read_2D(ccl_gpu_tex_object tex, float x, float y) const {
+ const uint tid(tex);
+ const uint sid(tex >> 32);
+ return metal_ancillaries->textures_2d[tid].tex.sample(metal_samplers[sid], float2(x, y));
+ }
+ template<>
+ inline __attribute__((__always_inline__))
+ float ccl_gpu_tex_object_read_2D(ccl_gpu_tex_object tex, float x, float y) const {
+ const uint tid(tex);
+ const uint sid(tex >> 32);
+ return metal_ancillaries->textures_2d[tid].tex.sample(metal_samplers[sid], float2(x, y)).x;
+ }
+
+ // texture3d
+ template<>
+ inline __attribute__((__always_inline__))
+ float4 ccl_gpu_tex_object_read_3D(ccl_gpu_tex_object tex, float x, float y, float z) const {
+ const uint tid(tex);
+ const uint sid(tex >> 32);
+ return metal_ancillaries->textures_3d[tid].tex.sample(metal_samplers[sid], float3(x, y, z));
+ }
+ template<>
+ inline __attribute__((__always_inline__))
+ float ccl_gpu_tex_object_read_3D(ccl_gpu_tex_object tex, float x, float y, float z) const {
+ const uint tid(tex);
+ const uint sid(tex >> 32);
+ return metal_ancillaries->textures_3d[tid].tex.sample(metal_samplers[sid], float3(x, y, z)).x;
+ }
+# include "kernel/device/gpu/image.h"
+
+ // clang-format on
diff --git a/intern/cycles/kernel/device/metal/context_end.h b/intern/cycles/kernel/device/metal/context_end.h
new file mode 100644
index 00000000000..e700f294440
--- /dev/null
+++ b/intern/cycles/kernel/device/metal/context_end.h
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+}
+; /* end of MetalKernelContext class definition */
+
+/* Silently redirect into the MetalKernelContext instance */
+/* NOTE: These macros will need maintaining as entry-points change. */
+
+#undef kernel_integrator_state
+#define kernel_integrator_state context.launch_params_metal.__integrator_state
diff --git a/intern/cycles/kernel/device/metal/globals.h b/intern/cycles/kernel/device/metal/globals.h
new file mode 100644
index 00000000000..1aea36589d0
--- /dev/null
+++ b/intern/cycles/kernel/device/metal/globals.h
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+/* Constant Globals */
+
+#include "kernel/types.h"
+#include "kernel/util/profiling.h"
+
+#include "kernel/integrator/state.h"
+
+CCL_NAMESPACE_BEGIN
+
+typedef struct KernelParamsMetal {
+
+#define KERNEL_TEX(type, name) ccl_global const type *name;
+#include "kernel/textures.h"
+#undef KERNEL_TEX
+
+ const IntegratorStateGPU __integrator_state;
+ const KernelData data;
+
+} KernelParamsMetal;
+
+typedef struct KernelGlobalsGPU {
+ int unused[1];
+} KernelGlobalsGPU;
+
+typedef ccl_global const KernelGlobalsGPU *ccl_restrict KernelGlobals;
+
+#define kernel_data launch_params_metal.data
+#define kernel_integrator_state launch_params_metal.__integrator_state
+
+/* data lookup defines */
+
+#define kernel_tex_fetch(tex, index) launch_params_metal.tex[index]
+#define kernel_tex_array(tex) launch_params_metal.tex
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/device/metal/kernel.metal b/intern/cycles/kernel/device/metal/kernel.metal
new file mode 100644
index 00000000000..6b77940660f
--- /dev/null
+++ b/intern/cycles/kernel/device/metal/kernel.metal
@@ -0,0 +1,765 @@
+/*
+ * 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.
+ */
+
+/* Metal kernel entry points */
+
+#include "kernel/device/metal/compat.h"
+#include "kernel/device/metal/globals.h"
+#include "kernel/device/gpu/kernel.h"
+
+/* MetalRT intersection handlers */
+#ifdef __METALRT__
+
+/* Return type for a bounding box intersection function. */
+struct BoundingBoxIntersectionResult
+{
+ bool accept [[accept_intersection]];
+ bool continue_search [[continue_search]];
+ float distance [[distance]];
+};
+
+/* Return type for a triangle intersection function. */
+struct TriangleIntersectionResult
+{
+ bool accept [[accept_intersection]];
+ bool continue_search [[continue_search]];
+};
+
+enum { METALRT_HIT_TRIANGLE, METALRT_HIT_BOUNDING_BOX };
+
+ccl_device_inline bool intersection_skip_self(ray_data const RaySelfPrimitives& self,
+ const int object,
+ const int prim)
+{
+ return (self.prim == prim) && (self.object == object);
+}
+
+ccl_device_inline bool intersection_skip_self_shadow(ray_data const RaySelfPrimitives& self,
+ const int object,
+ const int prim)
+{
+ return ((self.prim == prim) && (self.object == object)) ||
+ ((self.light_prim == prim) && (self.light_object == object));
+}
+
+ccl_device_inline bool intersection_skip_self_local(ray_data const RaySelfPrimitives& self,
+ const int prim)
+{
+ return (self.prim == prim);
+}
+
+template<typename TReturn, uint intersection_type>
+TReturn metalrt_local_hit(constant KernelParamsMetal &launch_params_metal,
+ ray_data MetalKernelContext::MetalRTIntersectionLocalPayload &payload,
+ const uint object,
+ const uint primitive_id,
+ const float2 barycentrics,
+ const float ray_tmax)
+{
+ TReturn result;
+
+#ifdef __BVH_LOCAL__
+ uint prim = primitive_id + kernel_tex_fetch(__object_prim_offset, object);
+
+ if ((object != payload.local_object) || intersection_skip_self_local(payload.self, prim)) {
+ /* Only intersect with matching object and skip self-intersecton. */
+ result.accept = false;
+ result.continue_search = true;
+ return result;
+ }
+
+ const short max_hits = payload.max_hits;
+ if (max_hits == 0) {
+ /* Special case for when no hit information is requested, just report that something was hit */
+ payload.result = true;
+ result.accept = true;
+ result.continue_search = false;
+ return result;
+ }
+
+ int hit = 0;
+ if (payload.has_lcg_state) {
+ for (short i = min(max_hits, short(payload.local_isect.num_hits)) - 1; i >= 0; --i) {
+ if (ray_tmax == payload.local_isect.hits[i].t) {
+ result.accept = false;
+ result.continue_search = true;
+ return result;
+ }
+ }
+
+ hit = payload.local_isect.num_hits++;
+
+ if (payload.local_isect.num_hits > max_hits) {
+ hit = lcg_step_uint(&payload.lcg_state) % payload.local_isect.num_hits;
+ if (hit >= max_hits) {
+ result.accept = false;
+ result.continue_search = true;
+ return result;
+ }
+ }
+ }
+ else {
+ if (payload.local_isect.num_hits && ray_tmax > payload.local_isect.hits[0].t) {
+ /* Record closest intersection only. Do not terminate ray here, since there is no guarantee about distance ordering in any-hit */
+ result.accept = false;
+ result.continue_search = true;
+ return result;
+ }
+
+ payload.local_isect.num_hits = 1;
+ }
+
+ ray_data Intersection *isect = &payload.local_isect.hits[hit];
+ isect->t = ray_tmax;
+ isect->prim = prim;
+ isect->object = object;
+ isect->type = kernel_tex_fetch(__objects, object).primitive_type;
+
+ isect->u = 1.0f - barycentrics.y - barycentrics.x;
+ isect->v = barycentrics.x;
+
+ /* Record geometric normal */
+ const uint tri_vindex = kernel_tex_fetch(__tri_vindex, isect->prim).w;
+ const float3 tri_a = float3(kernel_tex_fetch(__tri_verts, tri_vindex + 0));
+ const float3 tri_b = float3(kernel_tex_fetch(__tri_verts, tri_vindex + 1));
+ const float3 tri_c = float3(kernel_tex_fetch(__tri_verts, tri_vindex + 2));
+ payload.local_isect.Ng[hit] = normalize(cross(tri_b - tri_a, tri_c - tri_a));
+
+ /* Continue tracing (without this the trace call would return after the first hit) */
+ result.accept = false;
+ result.continue_search = true;
+ return result;
+#endif
+}
+
+[[intersection(triangle, triangle_data, METALRT_TAGS)]]
+TriangleIntersectionResult
+__anyhit__cycles_metalrt_local_hit_tri(constant KernelParamsMetal &launch_params_metal [[buffer(1)]],
+ ray_data MetalKernelContext::MetalRTIntersectionLocalPayload &payload [[payload]],
+ uint instance_id [[user_instance_id]],
+ uint primitive_id [[primitive_id]],
+ float2 barycentrics [[barycentric_coord]],
+ float ray_tmax [[distance]])
+{
+ return metalrt_local_hit<TriangleIntersectionResult, METALRT_HIT_TRIANGLE>(
+ launch_params_metal, payload, instance_id, primitive_id, barycentrics, ray_tmax);
+}
+
+[[intersection(bounding_box, triangle_data, METALRT_TAGS)]]
+BoundingBoxIntersectionResult
+__anyhit__cycles_metalrt_local_hit_box(const float ray_tmax [[max_distance]])
+{
+ /* unused function */
+ BoundingBoxIntersectionResult result;
+ result.distance = ray_tmax;
+ result.accept = false;
+ result.continue_search = false;
+ return result;
+}
+
+template<uint intersection_type>
+bool metalrt_shadow_all_hit(constant KernelParamsMetal &launch_params_metal,
+ ray_data MetalKernelContext::MetalRTIntersectionShadowPayload &payload,
+ uint object,
+ uint prim,
+ const float2 barycentrics,
+ const float ray_tmax)
+{
+#ifdef __SHADOW_RECORD_ALL__
+# ifdef __VISIBILITY_FLAG__
+ const uint visibility = payload.visibility;
+ if ((kernel_tex_fetch(__objects, object).visibility & visibility) == 0) {
+ /* continue search */
+ return true;
+ }
+# endif
+
+ if (intersection_skip_self_shadow(payload.self, object, prim)) {
+ /* continue search */
+ return true;
+ }
+
+ float u = 0.0f, v = 0.0f;
+ int type = 0;
+ if (intersection_type == METALRT_HIT_TRIANGLE) {
+ u = 1.0f - barycentrics.y - barycentrics.x;
+ v = barycentrics.x;
+ type = kernel_tex_fetch(__objects, object).primitive_type;
+ }
+# ifdef __HAIR__
+ else {
+ u = barycentrics.x;
+ v = barycentrics.y;
+
+ const KernelCurveSegment segment = kernel_tex_fetch(__curve_segments, prim);
+ type = segment.type;
+ prim = segment.prim;
+
+ /* Filter out curve endcaps */
+ if (u == 0.0f || u == 1.0f) {
+ /* continue search */
+ return true;
+ }
+ }
+# endif
+
+# ifndef __TRANSPARENT_SHADOWS__
+ /* No transparent shadows support compiled in, make opaque. */
+ payload.result = true;
+ /* terminate ray */
+ return false;
+# else
+ short max_hits = payload.max_hits;
+ short num_hits = payload.num_hits;
+ short num_recorded_hits = payload.num_recorded_hits;
+
+ MetalKernelContext context(launch_params_metal);
+
+ /* If no transparent shadows, all light is blocked and we can stop immediately. */
+ if (num_hits >= max_hits ||
+ !(context.intersection_get_shader_flags(NULL, prim, type) & SD_HAS_TRANSPARENT_SHADOW)) {
+ payload.result = true;
+ /* terminate ray */
+ return false;
+ }
+
+ /* Always use baked shadow transparency for curves. */
+ if (type & PRIMITIVE_CURVE) {
+ float throughput = payload.throughput;
+ throughput *= context.intersection_curve_shadow_transparency(nullptr, object, prim, u);
+ payload.throughput = throughput;
+ payload.num_hits += 1;
+
+ if (throughput < CURVE_SHADOW_TRANSPARENCY_CUTOFF) {
+ /* Accept result and terminate if throughput is sufficiently low */
+ payload.result = true;
+ return false;
+ }
+ else {
+ return true;
+ }
+ }
+
+ payload.num_hits += 1;
+ payload.num_recorded_hits += 1;
+
+ uint record_index = num_recorded_hits;
+
+ const IntegratorShadowState state = payload.state;
+
+ const uint max_record_hits = min(uint(max_hits), INTEGRATOR_SHADOW_ISECT_SIZE);
+ if (record_index >= max_record_hits) {
+ /* If maximum number of hits reached, find a hit to replace. */
+ float max_recorded_t = INTEGRATOR_STATE_ARRAY(state, shadow_isect, 0, t);
+ uint max_recorded_hit = 0;
+
+ for (int i = 1; i < max_record_hits; i++) {
+ const float isect_t = INTEGRATOR_STATE_ARRAY(state, shadow_isect, i, t);
+ if (isect_t > max_recorded_t) {
+ max_recorded_t = isect_t;
+ max_recorded_hit = i;
+ }
+ }
+
+ if (ray_tmax >= max_recorded_t) {
+ /* Accept hit, so that we don't consider any more hits beyond the distance of the
+ * current hit anymore. */
+ payload.result = true;
+ return true;
+ }
+
+ record_index = max_recorded_hit;
+ }
+
+ INTEGRATOR_STATE_ARRAY_WRITE(state, shadow_isect, record_index, u) = u;
+ INTEGRATOR_STATE_ARRAY_WRITE(state, shadow_isect, record_index, v) = v;
+ INTEGRATOR_STATE_ARRAY_WRITE(state, shadow_isect, record_index, t) = ray_tmax;
+ INTEGRATOR_STATE_ARRAY_WRITE(state, shadow_isect, record_index, prim) = prim;
+ INTEGRATOR_STATE_ARRAY_WRITE(state, shadow_isect, record_index, object) = object;
+ INTEGRATOR_STATE_ARRAY_WRITE(state, shadow_isect, record_index, type) = type;
+
+ /* Continue tracing. */
+# endif /* __TRANSPARENT_SHADOWS__ */
+#endif /* __SHADOW_RECORD_ALL__ */
+
+ return true;
+}
+
+[[intersection(triangle, triangle_data, METALRT_TAGS)]]
+TriangleIntersectionResult
+__anyhit__cycles_metalrt_shadow_all_hit_tri(constant KernelParamsMetal &launch_params_metal [[buffer(1)]],
+ ray_data MetalKernelContext::MetalRTIntersectionShadowPayload &payload [[payload]],
+ unsigned int object [[user_instance_id]],
+ unsigned int primitive_id [[primitive_id]],
+ float2 barycentrics [[barycentric_coord]],
+ float ray_tmax [[distance]])
+{
+ uint prim = primitive_id + kernel_tex_fetch(__object_prim_offset, object);
+
+ TriangleIntersectionResult result;
+ result.continue_search = metalrt_shadow_all_hit<METALRT_HIT_TRIANGLE>(
+ launch_params_metal, payload, object, prim, barycentrics, ray_tmax);
+ result.accept = !result.continue_search;
+ return result;
+}
+
+[[intersection(bounding_box, triangle_data, METALRT_TAGS)]]
+BoundingBoxIntersectionResult
+__anyhit__cycles_metalrt_shadow_all_hit_box(const float ray_tmax [[max_distance]])
+{
+ /* unused function */
+ BoundingBoxIntersectionResult result;
+ result.distance = ray_tmax;
+ result.accept = false;
+ result.continue_search = false;
+ return result;
+}
+
+template<typename TReturnType, uint intersection_type>
+inline TReturnType metalrt_visibility_test(constant KernelParamsMetal &launch_params_metal,
+ ray_data MetalKernelContext::MetalRTIntersectionPayload &payload,
+ const uint object,
+ const uint prim,
+ const float u)
+{
+ TReturnType result;
+
+# ifdef __HAIR__
+ if (intersection_type == METALRT_HIT_BOUNDING_BOX) {
+ /* Filter out curve endcaps. */
+ if (u == 0.0f || u == 1.0f) {
+ result.accept = false;
+ result.continue_search = true;
+ return result;
+ }
+ }
+# endif
+
+ uint visibility = payload.visibility;
+# ifdef __VISIBILITY_FLAG__
+ if ((kernel_tex_fetch(__objects, object).visibility & visibility) == 0) {
+ result.accept = false;
+ result.continue_search = true;
+ return result;
+ }
+# endif
+
+ /* Shadow ray early termination. */
+ if (visibility & PATH_RAY_SHADOW_OPAQUE) {
+ if (intersection_skip_self_shadow(payload.self, object, prim)) {
+ result.accept = false;
+ result.continue_search = true;
+ return result;
+ }
+ else {
+ result.accept = true;
+ result.continue_search = false;
+ return result;
+ }
+ }
+ else {
+ if (intersection_skip_self(payload.self, object, prim)) {
+ result.accept = false;
+ result.continue_search = true;
+ return result;
+ }
+ }
+
+ result.accept = true;
+ result.continue_search = true;
+ return result;
+}
+
+[[intersection(triangle, triangle_data, METALRT_TAGS)]]
+TriangleIntersectionResult
+__anyhit__cycles_metalrt_visibility_test_tri(constant KernelParamsMetal &launch_params_metal [[buffer(1)]],
+ ray_data MetalKernelContext::MetalRTIntersectionPayload &payload [[payload]],
+ unsigned int object [[user_instance_id]],
+ unsigned int primitive_id [[primitive_id]])
+{
+ uint prim = primitive_id + kernel_tex_fetch(__object_prim_offset, object);
+ TriangleIntersectionResult result = metalrt_visibility_test<TriangleIntersectionResult, METALRT_HIT_TRIANGLE>(
+ launch_params_metal, payload, object, prim, 0.0f);
+ if (result.accept) {
+ payload.prim = prim;
+ payload.type = kernel_tex_fetch(__objects, object).primitive_type;
+ }
+ return result;
+}
+
+[[intersection(bounding_box, triangle_data, METALRT_TAGS)]]
+BoundingBoxIntersectionResult
+__anyhit__cycles_metalrt_visibility_test_box(const float ray_tmax [[max_distance]])
+{
+ /* Unused function */
+ BoundingBoxIntersectionResult result;
+ result.accept = false;
+ result.continue_search = true;
+ result.distance = ray_tmax;
+ return result;
+}
+
+#ifdef __HAIR__
+ccl_device_inline
+void metalrt_intersection_curve(constant KernelParamsMetal &launch_params_metal,
+ ray_data MetalKernelContext::MetalRTIntersectionPayload &payload,
+ const uint object,
+ const uint prim,
+ const uint type,
+ const float3 ray_origin,
+ const float3 ray_direction,
+ float time,
+ const float ray_tmax,
+ thread BoundingBoxIntersectionResult &result)
+{
+# ifdef __VISIBILITY_FLAG__
+ const uint visibility = payload.visibility;
+ if ((kernel_tex_fetch(__objects, object).visibility & visibility) == 0) {
+ return;
+ }
+# endif
+
+ float3 P = ray_origin;
+ float3 dir = ray_direction;
+
+ /* The direction is not normalized by default, but the curve intersection routine expects that */
+ float len;
+ dir = normalize_len(dir, &len);
+
+ Intersection isect;
+ isect.t = ray_tmax;
+ /* Transform maximum distance into object space. */
+ if (isect.t != FLT_MAX)
+ isect.t *= len;
+
+ MetalKernelContext context(launch_params_metal);
+ if (context.curve_intersect(NULL, &isect, P, dir, isect.t, object, prim, time, type)) {
+ result = metalrt_visibility_test<BoundingBoxIntersectionResult, METALRT_HIT_BOUNDING_BOX>(
+ launch_params_metal, payload, object, prim, isect.u);
+ if (result.accept) {
+ result.distance = isect.t / len;
+ payload.u = isect.u;
+ payload.v = isect.v;
+ payload.prim = prim;
+ payload.type = type;
+ }
+ }
+}
+
+ccl_device_inline
+void metalrt_intersection_curve_shadow(constant KernelParamsMetal &launch_params_metal,
+ ray_data MetalKernelContext::MetalRTIntersectionShadowPayload &payload,
+ const uint object,
+ const uint prim,
+ const uint type,
+ const float3 ray_origin,
+ const float3 ray_direction,
+ float time,
+ const float ray_tmax,
+ thread BoundingBoxIntersectionResult &result)
+{
+ const uint visibility = payload.visibility;
+
+ float3 P = ray_origin;
+ float3 dir = ray_direction;
+
+ /* The direction is not normalized by default, but the curve intersection routine expects that */
+ float len;
+ dir = normalize_len(dir, &len);
+
+ Intersection isect;
+ isect.t = ray_tmax;
+ /* Transform maximum distance into object space */
+ if (isect.t != FLT_MAX)
+ isect.t *= len;
+
+ MetalKernelContext context(launch_params_metal);
+ if (context.curve_intersect(NULL, &isect, P, dir, isect.t, object, prim, time, type)) {
+ result.continue_search = metalrt_shadow_all_hit<METALRT_HIT_BOUNDING_BOX>(
+ launch_params_metal, payload, object, prim, float2(isect.u, isect.v), ray_tmax);
+ result.accept = !result.continue_search;
+
+ if (result.accept) {
+ result.distance = isect.t / len;
+ }
+ }
+}
+
+[[intersection(bounding_box, triangle_data, METALRT_TAGS)]]
+BoundingBoxIntersectionResult
+__intersection__curve_ribbon(constant KernelParamsMetal &launch_params_metal [[buffer(1)]],
+ ray_data MetalKernelContext::MetalRTIntersectionPayload &payload [[payload]],
+ const uint object [[user_instance_id]],
+ const uint primitive_id [[primitive_id]],
+ const float3 ray_origin [[origin]],
+ const float3 ray_direction [[direction]],
+ const float ray_tmax [[max_distance]])
+{
+ uint prim = primitive_id + kernel_tex_fetch(__object_prim_offset, object);
+ const KernelCurveSegment segment = kernel_tex_fetch(__curve_segments, prim);
+
+ BoundingBoxIntersectionResult result;
+ result.accept = false;
+ result.continue_search = true;
+ result.distance = ray_tmax;
+
+ if (segment.type & PRIMITIVE_CURVE_RIBBON) {
+ metalrt_intersection_curve(launch_params_metal, payload, object, segment.prim, segment.type, ray_origin, ray_direction,
+# if defined(__METALRT_MOTION__)
+ payload.time,
+# else
+ 0.0f,
+# endif
+ ray_tmax, result);
+ }
+
+ return result;
+}
+
+[[intersection(bounding_box, triangle_data, METALRT_TAGS)]]
+BoundingBoxIntersectionResult
+__intersection__curve_ribbon_shadow(constant KernelParamsMetal &launch_params_metal [[buffer(1)]],
+ ray_data MetalKernelContext::MetalRTIntersectionShadowPayload &payload [[payload]],
+ const uint object [[user_instance_id]],
+ const uint primitive_id [[primitive_id]],
+ const float3 ray_origin [[origin]],
+ const float3 ray_direction [[direction]],
+ const float ray_tmax [[max_distance]])
+{
+ uint prim = primitive_id + kernel_tex_fetch(__object_prim_offset, object);
+ const KernelCurveSegment segment = kernel_tex_fetch(__curve_segments, prim);
+
+ BoundingBoxIntersectionResult result;
+ result.accept = false;
+ result.continue_search = true;
+ result.distance = ray_tmax;
+
+ if (segment.type & PRIMITIVE_CURVE_RIBBON) {
+ metalrt_intersection_curve_shadow(launch_params_metal, payload, object, segment.prim, segment.type, ray_origin, ray_direction,
+# if defined(__METALRT_MOTION__)
+ payload.time,
+# else
+ 0.0f,
+# endif
+ ray_tmax, result);
+ }
+
+ return result;
+}
+
+[[intersection(bounding_box, triangle_data, METALRT_TAGS)]]
+BoundingBoxIntersectionResult
+__intersection__curve_all(constant KernelParamsMetal &launch_params_metal [[buffer(1)]],
+ ray_data MetalKernelContext::MetalRTIntersectionPayload &payload [[payload]],
+ const uint object [[user_instance_id]],
+ const uint primitive_id [[primitive_id]],
+ const float3 ray_origin [[origin]],
+ const float3 ray_direction [[direction]],
+ const float ray_tmax [[max_distance]])
+{
+ uint prim = primitive_id + kernel_tex_fetch(__object_prim_offset, object);
+ const KernelCurveSegment segment = kernel_tex_fetch(__curve_segments, prim);
+
+ BoundingBoxIntersectionResult result;
+ result.accept = false;
+ result.continue_search = true;
+ result.distance = ray_tmax;
+ metalrt_intersection_curve(launch_params_metal, payload, object, segment.prim, segment.type, ray_origin, ray_direction,
+# if defined(__METALRT_MOTION__)
+ payload.time,
+# else
+ 0.0f,
+# endif
+ ray_tmax, result);
+
+ return result;
+}
+
+[[intersection(bounding_box, triangle_data, METALRT_TAGS)]]
+BoundingBoxIntersectionResult
+__intersection__curve_all_shadow(constant KernelParamsMetal &launch_params_metal [[buffer(1)]],
+ ray_data MetalKernelContext::MetalRTIntersectionShadowPayload &payload [[payload]],
+ const uint object [[user_instance_id]],
+ const uint primitive_id [[primitive_id]],
+ const float3 ray_origin [[origin]],
+ const float3 ray_direction [[direction]],
+ const float ray_tmax [[max_distance]])
+{
+ uint prim = primitive_id + kernel_tex_fetch(__object_prim_offset, object);
+ const KernelCurveSegment segment = kernel_tex_fetch(__curve_segments, prim);
+
+ BoundingBoxIntersectionResult result;
+ result.accept = false;
+ result.continue_search = true;
+ result.distance = ray_tmax;
+
+ metalrt_intersection_curve_shadow(launch_params_metal, payload, object, segment.prim, segment.type, ray_origin, ray_direction,
+# if defined(__METALRT_MOTION__)
+ payload.time,
+# else
+ 0.0f,
+# endif
+ ray_tmax, result);
+
+ return result;
+}
+#endif /* __HAIR__ */
+
+#ifdef __POINTCLOUD__
+ccl_device_inline
+void metalrt_intersection_point(constant KernelParamsMetal &launch_params_metal,
+ ray_data MetalKernelContext::MetalRTIntersectionPayload &payload,
+ const uint object,
+ const uint prim,
+ const uint type,
+ const float3 ray_origin,
+ const float3 ray_direction,
+ float time,
+ const float ray_tmax,
+ thread BoundingBoxIntersectionResult &result)
+{
+# ifdef __VISIBILITY_FLAG__
+ const uint visibility = payload.visibility;
+ if ((kernel_tex_fetch(__objects, object).visibility & visibility) == 0) {
+ return;
+ }
+# endif
+
+ float3 P = ray_origin;
+ float3 dir = ray_direction;
+
+ /* The direction is not normalized by default, but the point intersection routine expects that */
+ float len;
+ dir = normalize_len(dir, &len);
+
+ Intersection isect;
+ isect.t = ray_tmax;
+ /* Transform maximum distance into object space. */
+ if (isect.t != FLT_MAX)
+ isect.t *= len;
+
+ MetalKernelContext context(launch_params_metal);
+ if (context.point_intersect(NULL, &isect, P, dir, isect.t, object, prim, time, type)) {
+ result = metalrt_visibility_test<BoundingBoxIntersectionResult, METALRT_HIT_BOUNDING_BOX>(
+ launch_params_metal, payload, object, prim, isect.u);
+ if (result.accept) {
+ result.distance = isect.t / len;
+ payload.u = isect.u;
+ payload.v = isect.v;
+ payload.prim = prim;
+ payload.type = type;
+ }
+ }
+}
+
+ccl_device_inline
+void metalrt_intersection_point_shadow(constant KernelParamsMetal &launch_params_metal,
+ ray_data MetalKernelContext::MetalRTIntersectionShadowPayload &payload,
+ const uint object,
+ const uint prim,
+ const uint type,
+ const float3 ray_origin,
+ const float3 ray_direction,
+ float time,
+ const float ray_tmax,
+ thread BoundingBoxIntersectionResult &result)
+{
+ const uint visibility = payload.visibility;
+
+ float3 P = ray_origin;
+ float3 dir = ray_direction;
+
+ /* The direction is not normalized by default, but the point intersection routine expects that */
+ float len;
+ dir = normalize_len(dir, &len);
+
+ Intersection isect;
+ isect.t = ray_tmax;
+ /* Transform maximum distance into object space */
+ if (isect.t != FLT_MAX)
+ isect.t *= len;
+
+ MetalKernelContext context(launch_params_metal);
+ if (context.point_intersect(NULL, &isect, P, dir, isect.t, object, prim, time, type)) {
+ result.continue_search = metalrt_shadow_all_hit<METALRT_HIT_BOUNDING_BOX>(
+ launch_params_metal, payload, object, prim, float2(isect.u, isect.v), ray_tmax);
+ result.accept = !result.continue_search;
+
+ if (result.accept) {
+ result.distance = isect.t / len;
+ }
+ }
+}
+
+[[intersection(bounding_box, triangle_data, METALRT_TAGS)]]
+BoundingBoxIntersectionResult
+__intersection__point(constant KernelParamsMetal &launch_params_metal [[buffer(1)]],
+ ray_data MetalKernelContext::MetalRTIntersectionPayload &payload [[payload]],
+ const uint object [[user_instance_id]],
+ const uint primitive_id [[primitive_id]],
+ const float3 ray_origin [[origin]],
+ const float3 ray_direction [[direction]],
+ const float ray_tmax [[max_distance]])
+{
+ const uint prim = primitive_id + kernel_tex_fetch(__object_prim_offset, object);
+ const int type = kernel_tex_fetch(__objects, object).primitive_type;
+
+ BoundingBoxIntersectionResult result;
+ result.accept = false;
+ result.continue_search = true;
+ result.distance = ray_tmax;
+
+ metalrt_intersection_point(launch_params_metal, payload, object, prim, type, ray_origin, ray_direction,
+# if defined(__METALRT_MOTION__)
+ payload.time,
+# else
+ 0.0f,
+# endif
+ ray_tmax, result);
+
+ return result;
+}
+
+[[intersection(bounding_box, triangle_data, METALRT_TAGS)]]
+BoundingBoxIntersectionResult
+__intersection__point_shadow(constant KernelParamsMetal &launch_params_metal [[buffer(1)]],
+ ray_data MetalKernelContext::MetalRTIntersectionShadowPayload &payload [[payload]],
+ const uint object [[user_instance_id]],
+ const uint primitive_id [[primitive_id]],
+ const float3 ray_origin [[origin]],
+ const float3 ray_direction [[direction]],
+ const float ray_tmax [[max_distance]])
+{
+ const uint prim = primitive_id + kernel_tex_fetch(__object_prim_offset, object);
+ const int type = kernel_tex_fetch(__objects, object).primitive_type;
+
+ BoundingBoxIntersectionResult result;
+ result.accept = false;
+ result.continue_search = true;
+ result.distance = ray_tmax;
+
+ metalrt_intersection_point_shadow(launch_params_metal, payload, object, prim, type, ray_origin, ray_direction,
+# if defined(__METALRT_MOTION__)
+ payload.time,
+# else
+ 0.0f,
+# endif
+ ray_tmax, result);
+
+ return result;
+}
+#endif /* __POINTCLOUD__ */
+#endif /* __METALRT__ */
diff --git a/intern/cycles/kernel/device/optix/compat.h b/intern/cycles/kernel/device/optix/compat.h
index fb9e094b535..db4233624b9 100644
--- a/intern/cycles/kernel/device/optix/compat.h
+++ b/intern/cycles/kernel/device/optix/compat.h
@@ -21,6 +21,7 @@
#include <optix.h>
#define __KERNEL_GPU__
+#define __KERNEL_GPU_RAYTRACING__
#define __KERNEL_CUDA__ /* OptiX kernels are implicitly CUDA kernels too */
#define __KERNEL_OPTIX__
#define CCL_NAMESPACE_BEGIN
@@ -49,16 +50,16 @@ typedef unsigned long long uint64_t;
__device__ __forceinline__ // Function calls are bad for OptiX performance, so inline everything
#define ccl_device_inline ccl_device
#define ccl_device_forceinline ccl_device
+#define ccl_device_inline_method ccl_device
#define ccl_device_noinline __device__ __noinline__
#define ccl_device_noinline_cpu ccl_device
#define ccl_global
-#define ccl_static_constant __constant__
+#define ccl_inline_constant __constant__
#define ccl_device_constant __constant__ __device__
#define ccl_constant const
#define ccl_gpu_shared __shared__
#define ccl_private
#define ccl_may_alias
-#define ccl_addr_space
#define ccl_restrict __restrict__
#define ccl_loop_no_unroll
#define ccl_align(n) __align__(n)
@@ -77,6 +78,7 @@ typedef unsigned long long uint64_t;
#define ccl_gpu_block_idx_x (blockIdx.x)
#define ccl_gpu_grid_dim_x (gridDim.x)
#define ccl_gpu_warp_size (warpSize)
+#define ccl_gpu_thread_mask(thread_warp) uint(0xFFFFFFFF >> (ccl_gpu_warp_size - thread_warp))
#define ccl_gpu_global_id_x() (ccl_gpu_block_idx_x * ccl_gpu_block_dim_x + ccl_gpu_thread_idx_x)
#define ccl_gpu_global_size_x() (ccl_gpu_grid_dim_x * ccl_gpu_block_dim_x)
@@ -86,7 +88,6 @@ typedef unsigned long long uint64_t;
#define ccl_gpu_syncthreads() __syncthreads()
#define ccl_gpu_ballot(predicate) __ballot_sync(0xFFFFFFFF, predicate)
#define ccl_gpu_shfl_down_sync(mask, var, detla) __shfl_down_sync(mask, var, detla)
-#define ccl_gpu_popc(x) __popc(x)
/* GPU texture objects */
@@ -121,7 +122,14 @@ __device__ half __float2half(const float f)
return val;
}
+__device__ float __half2float(const half h)
+{
+ float val;
+ asm("{ cvt.f32.f16 %0, %1;}\n" : "=f"(val) : "h"(h));
+ return val;
+}
+
/* 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 7d898ed5d91..e9b72369cd5 100644
--- a/intern/cycles/kernel/device/optix/globals.h
+++ b/intern/cycles/kernel/device/optix/globals.h
@@ -18,18 +18,20 @@
#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
/* Not actually used, just a NULL pointer that gets passed everywhere, which we
* hope gets optimized out by the compiler. */
-struct KernelGlobals {
+struct KernelGlobalsGPU {
int unused[1];
};
+typedef ccl_global const KernelGlobalsGPU *ccl_restrict KernelGlobals;
/* Launch parameters */
struct KernelParamsOptiX {
@@ -40,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 7a79e0c4823..8e3d57bff8a 100644
--- a/intern/cycles/kernel/device/optix/kernel.cu
+++ b/intern/cycles/kernel/device/optix/kernel.cu
@@ -21,42 +21,44 @@
#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/tables.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
+#define OPTIX_DEFINE_ABI_VERSION_ONLY
+#include <optix_function_table.h>
+
template<typename T> ccl_device_forceinline T *get_payload_ptr_0()
{
- return (T *)(((uint64_t)optixGetPayload_1() << 32) | optixGetPayload_0());
+ return pointer_unpack_from_uint<T>(optixGetPayload_0(), optixGetPayload_1());
}
template<typename T> ccl_device_forceinline T *get_payload_ptr_2()
{
- return (T *)(((uint64_t)optixGetPayload_3() << 32) | optixGetPayload_2());
+ return pointer_unpack_from_uint<T>(optixGetPayload_2(), optixGetPayload_3());
+}
+
+template<typename T> ccl_device_forceinline T *get_payload_ptr_6()
+{
+ return (T *)(((uint64_t)optixGetPayload_7() << 32) | optixGetPayload_6());
}
-template<bool always = false> ccl_device_forceinline uint get_object_id()
+ccl_device_forceinline int get_object_id()
{
#ifdef __OBJECT_MOTION__
- /* Always get the the instance ID from the TLAS.
+ /* Always get the instance ID from the TLAS
* There might be a motion transform node between TLAS and BLAS which does not have one. */
- uint object = optixGetInstanceIdFromHandle(optixGetTransformListHandle(0));
+ return optixGetInstanceIdFromHandle(optixGetTransformListHandle(0));
#else
- uint object = optixGetInstanceId();
+ return optixGetInstanceId();
#endif
- /* Choose between always returning object ID or only for instances. */
- if (always || (object & 1) == 0)
- /* Can just remove the low bit since instance always contains object ID. */
- return object >> 1;
- else
- /* Set to OBJECT_NONE if this is not an instanced object. */
- return OBJECT_NONE;
}
extern "C" __global__ void __raygen__kernel_optix_integrator_intersect_closest()
@@ -64,7 +66,7 @@ extern "C" __global__ void __raygen__kernel_optix_integrator_intersect_closest()
const int global_index = optixGetLaunchIndex().x;
const int path_index = (__params.path_index_array) ? __params.path_index_array[global_index] :
global_index;
- integrator_intersect_closest(nullptr, path_index);
+ integrator_intersect_closest(nullptr, path_index, __params.render_buffer);
}
extern "C" __global__ void __raygen__kernel_optix_integrator_intersect_shadow()
@@ -100,20 +102,26 @@ extern "C" __global__ void __miss__kernel_optix_miss()
extern "C" __global__ void __anyhit__kernel_optix_local_hit()
{
-#ifdef __HAIR__
+#if defined(__HAIR__) || defined(__POINTCLOUD__)
if (!optixIsTriangleHit()) {
- /* Ignore curves. */
+ /* Ignore curves and points. */
return optixIgnoreIntersection();
}
#endif
#ifdef __BVH_LOCAL__
- const uint object = get_object_id<true>();
+ const int object = get_object_id();
if (object != optixGetPayload_4() /* local_object */) {
/* Only intersect with matching object. */
return optixIgnoreIntersection();
}
+ const int prim = optixGetPrimitiveIndex();
+ ccl_private Ray *const ray = get_payload_ptr_6<Ray>();
+ if (intersection_skip_self_local(ray->self, prim)) {
+ return optixIgnoreIntersection();
+ }
+
const uint max_hits = optixGetPayload_5();
if (max_hits == 0) {
/* Special case for when no hit information is requested, just report that something was hit */
@@ -154,19 +162,19 @@ extern "C" __global__ void __anyhit__kernel_optix_local_hit()
Intersection *isect = &local_isect->hits[hit];
isect->t = optixGetRayTmax();
- isect->prim = optixGetPrimitiveIndex();
+ isect->prim = prim;
isect->object = get_object_id();
- isect->type = kernel_tex_fetch(__prim_type, isect->prim);
+ isect->type = kernel_tex_fetch(__objects, isect->object).primitive_type;
const float2 barycentrics = optixGetTriangleBarycentrics();
isect->u = 1.0f - barycentrics.y - barycentrics.x;
isect->v = barycentrics.x;
/* Record geometric normal. */
- const uint tri_vindex = kernel_tex_fetch(__prim_tri_index, isect->prim);
- const float3 tri_a = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex + 0));
- const float3 tri_b = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex + 1));
- const float3 tri_c = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex + 2));
+ const uint tri_vindex = kernel_tex_fetch(__tri_vindex, prim).w;
+ const float3 tri_a = kernel_tex_fetch(__tri_verts, tri_vindex + 0);
+ const float3 tri_b = kernel_tex_fetch(__tri_verts, tri_vindex + 1);
+ const float3 tri_c = kernel_tex_fetch(__tri_verts, tri_vindex + 2);
local_isect->Ng[hit] = normalize(cross(tri_b - tri_a, tri_c - tri_a));
/* Continue tracing (without this the trace call would return after the first hit). */
@@ -177,167 +185,239 @@ extern "C" __global__ void __anyhit__kernel_optix_local_hit()
extern "C" __global__ void __anyhit__kernel_optix_shadow_all_hit()
{
#ifdef __SHADOW_RECORD_ALL__
- bool ignore_intersection = false;
-
- const uint prim = optixGetPrimitiveIndex();
+ int prim = optixGetPrimitiveIndex();
+ const uint object = get_object_id();
# ifdef __VISIBILITY_FLAG__
const uint visibility = optixGetPayload_4();
- if ((kernel_tex_fetch(__prim_visibility, prim) & visibility) == 0) {
- ignore_intersection = true;
+ if ((kernel_tex_fetch(__objects, object).visibility & visibility) == 0) {
+ return optixIgnoreIntersection();
}
# endif
+ ccl_private Ray *const ray = get_payload_ptr_6<Ray>();
+ if (intersection_skip_self_shadow(ray->self, object, prim)) {
+ return optixIgnoreIntersection();
+ }
+
float u = 0.0f, v = 0.0f;
+ int type = 0;
if (optixIsTriangleHit()) {
const float2 barycentrics = optixGetTriangleBarycentrics();
u = 1.0f - barycentrics.y - barycentrics.x;
v = barycentrics.x;
+ type = kernel_tex_fetch(__objects, object).primitive_type;
}
# ifdef __HAIR__
- else {
+ else if ((optixGetHitKind() & (~PRIMITIVE_MOTION)) != PRIMITIVE_POINT) {
u = __uint_as_float(optixGetAttribute_0());
v = __uint_as_float(optixGetAttribute_1());
+ const KernelCurveSegment segment = kernel_tex_fetch(__curve_segments, prim);
+ type = segment.type;
+ prim = segment.prim;
+
+# if OPTIX_ABI_VERSION < 55
/* Filter out curve endcaps. */
if (u == 0.0f || u == 1.0f) {
- ignore_intersection = true;
+ return optixIgnoreIntersection();
}
+# endif
}
# endif
+ else {
+ type = kernel_tex_fetch(__objects, object).primitive_type;
+ u = 0.0f;
+ v = 0.0f;
+ }
- int num_hits = optixGetPayload_2();
- int record_index = num_hits;
- const int max_hits = optixGetPayload_3();
+# ifndef __TRANSPARENT_SHADOWS__
+ /* No transparent shadows support compiled in, make opaque. */
+ optixSetPayload_5(true);
+ return optixTerminateRay();
+# else
+ const uint max_hits = optixGetPayload_3();
+ const uint num_hits_packed = optixGetPayload_2();
+ const uint num_recorded_hits = uint16_unpack_from_uint_0(num_hits_packed);
+ const uint num_hits = uint16_unpack_from_uint_1(num_hits_packed);
+
+ /* If no transparent shadows, all light is blocked and we can stop immediately. */
+ if (num_hits >= max_hits ||
+ !(intersection_get_shader_flags(NULL, prim, type) & SD_HAS_TRANSPARENT_SHADOW)) {
+ optixSetPayload_5(true);
+ return optixTerminateRay();
+ }
+
+ /* Always use baked shadow transparency for curves. */
+ if (type & PRIMITIVE_CURVE) {
+ float throughput = __uint_as_float(optixGetPayload_1());
+ throughput *= intersection_curve_shadow_transparency(nullptr, object, prim, u);
+ optixSetPayload_1(__float_as_uint(throughput));
+ optixSetPayload_2(uint16_pack_to_uint(num_recorded_hits, num_hits + 1));
- if (!ignore_intersection) {
- optixSetPayload_2(num_hits + 1);
+ if (throughput < CURVE_SHADOW_TRANSPARENCY_CUTOFF) {
+ optixSetPayload_5(true);
+ return optixTerminateRay();
+ }
+ else {
+ /* Continue tracing. */
+ optixIgnoreIntersection();
+ return;
+ }
}
- Intersection *const isect_array = get_payload_ptr_0<Intersection>();
+ /* Record transparent intersection. */
+ optixSetPayload_2(uint16_pack_to_uint(num_recorded_hits + 1, num_hits + 1));
+
+ uint record_index = num_recorded_hits;
+
+ const IntegratorShadowState state = optixGetPayload_0();
-# ifdef __TRANSPARENT_SHADOWS__
- if (num_hits >= max_hits) {
+ const uint max_record_hits = min(max_hits, INTEGRATOR_SHADOW_ISECT_SIZE);
+ if (record_index >= max_record_hits) {
/* If maximum number of hits reached, find a hit to replace. */
- const int num_recorded_hits = min(max_hits, num_hits);
- float max_recorded_t = isect_array[0].t;
- int max_recorded_hit = 0;
+ float max_recorded_t = INTEGRATOR_STATE_ARRAY(state, shadow_isect, 0, t);
+ uint max_recorded_hit = 0;
- for (int i = 1; i < num_recorded_hits; i++) {
- if (isect_array[i].t > max_recorded_t) {
- max_recorded_t = isect_array[i].t;
+ for (int i = 1; i < max_record_hits; i++) {
+ const float isect_t = INTEGRATOR_STATE_ARRAY(state, shadow_isect, i, t);
+ if (isect_t > max_recorded_t) {
+ max_recorded_t = isect_t;
max_recorded_hit = i;
}
}
if (optixGetRayTmax() >= max_recorded_t) {
- /* Accept hit, so that OptiX won't consider any more hits beyond the distance of the current
- * hit anymore. */
+ /* Accept hit, so that OptiX won't consider any more hits beyond the distance of the
+ * current hit anymore. */
return;
}
record_index = max_recorded_hit;
}
-# endif
- if (!ignore_intersection) {
- Intersection *const isect = isect_array + record_index;
- isect->u = u;
- isect->v = v;
- isect->t = optixGetRayTmax();
- isect->prim = prim;
- isect->object = get_object_id();
- isect->type = kernel_tex_fetch(__prim_type, prim);
-
-# ifdef __TRANSPARENT_SHADOWS__
- /* Detect if this surface has a shader with transparent shadows. */
- if (!shader_transparent_shadow(NULL, isect) || max_hits == 0) {
-# endif
- /* If no transparent shadows, all light is blocked and we can stop immediately. */
- optixSetPayload_5(true);
- return optixTerminateRay();
-# ifdef __TRANSPARENT_SHADOWS__
- }
-# endif
- }
+ INTEGRATOR_STATE_ARRAY_WRITE(state, shadow_isect, record_index, u) = u;
+ INTEGRATOR_STATE_ARRAY_WRITE(state, shadow_isect, record_index, v) = v;
+ INTEGRATOR_STATE_ARRAY_WRITE(state, shadow_isect, record_index, t) = optixGetRayTmax();
+ INTEGRATOR_STATE_ARRAY_WRITE(state, shadow_isect, record_index, prim) = prim;
+ INTEGRATOR_STATE_ARRAY_WRITE(state, shadow_isect, record_index, object) = object;
+ INTEGRATOR_STATE_ARRAY_WRITE(state, shadow_isect, record_index, type) = type;
/* Continue tracing. */
optixIgnoreIntersection();
-#endif
+# endif /* __TRANSPARENT_SHADOWS__ */
+#endif /* __SHADOW_RECORD_ALL__ */
}
extern "C" __global__ void __anyhit__kernel_optix_volume_test()
{
-#ifdef __HAIR__
+#if defined(__HAIR__) || defined(__POINTCLOUD__)
if (!optixIsTriangleHit()) {
/* Ignore curves. */
return optixIgnoreIntersection();
}
#endif
+ const uint object = get_object_id();
#ifdef __VISIBILITY_FLAG__
- const uint prim = optixGetPrimitiveIndex();
const uint visibility = optixGetPayload_4();
- if ((kernel_tex_fetch(__prim_visibility, prim) & visibility) == 0) {
+ if ((kernel_tex_fetch(__objects, object).visibility & visibility) == 0) {
return optixIgnoreIntersection();
}
#endif
- const uint object = get_object_id<true>();
if ((kernel_tex_fetch(__object_flag, object) & SD_OBJECT_HAS_VOLUME) == 0) {
return optixIgnoreIntersection();
}
+
+ const int prim = optixGetPrimitiveIndex();
+ ccl_private Ray *const ray = get_payload_ptr_6<Ray>();
+ if (intersection_skip_self(ray->self, object, prim)) {
+ return optixIgnoreIntersection();
+ }
}
extern "C" __global__ void __anyhit__kernel_optix_visibility_test()
{
#ifdef __HAIR__
- if (!optixIsTriangleHit()) {
+# if OPTIX_ABI_VERSION < 55
+ if (optixGetPrimitiveType() == OPTIX_PRIMITIVE_TYPE_ROUND_CUBIC_BSPLINE) {
/* Filter out curve endcaps. */
const float u = __uint_as_float(optixGetAttribute_0());
if (u == 0.0f || u == 1.0f) {
return optixIgnoreIntersection();
}
}
+# endif
#endif
-#ifdef __VISIBILITY_FLAG__
- const uint prim = optixGetPrimitiveIndex();
+ const uint object = get_object_id();
const uint visibility = optixGetPayload_4();
- if ((kernel_tex_fetch(__prim_visibility, prim) & visibility) == 0) {
+#ifdef __VISIBILITY_FLAG__
+ if ((kernel_tex_fetch(__objects, object).visibility & visibility) == 0) {
return optixIgnoreIntersection();
}
+#endif
+
+ const int prim = optixGetPrimitiveIndex();
+ ccl_private Ray *const ray = get_payload_ptr_6<Ray>();
- /* Shadow ray early termination. */
if (visibility & PATH_RAY_SHADOW_OPAQUE) {
- return optixTerminateRay();
+ if (intersection_skip_self_shadow(ray->self, object, prim)) {
+ return optixIgnoreIntersection();
+ }
+ else {
+ /* Shadow ray early termination. */
+ return optixTerminateRay();
+ }
+ }
+ else {
+ if (intersection_skip_self(ray->self, object, prim)) {
+ return optixIgnoreIntersection();
+ }
}
-#endif
}
extern "C" __global__ void __closesthit__kernel_optix_hit()
{
+ const int object = get_object_id();
+ const int prim = optixGetPrimitiveIndex();
+
optixSetPayload_0(__float_as_uint(optixGetRayTmax())); /* Intersection distance */
- optixSetPayload_3(optixGetPrimitiveIndex());
- optixSetPayload_4(get_object_id());
- /* Can be PRIMITIVE_TRIANGLE and PRIMITIVE_MOTION_TRIANGLE or curve type and segment index. */
- optixSetPayload_5(kernel_tex_fetch(__prim_type, optixGetPrimitiveIndex()));
+ optixSetPayload_4(object);
if (optixIsTriangleHit()) {
const float2 barycentrics = optixGetTriangleBarycentrics();
optixSetPayload_1(__float_as_uint(1.0f - barycentrics.y - barycentrics.x));
optixSetPayload_2(__float_as_uint(barycentrics.x));
+ optixSetPayload_3(prim);
+ optixSetPayload_5(kernel_tex_fetch(__objects, object).primitive_type);
}
- else {
+ else if ((optixGetHitKind() & (~PRIMITIVE_MOTION)) != PRIMITIVE_POINT) {
+ const KernelCurveSegment segment = kernel_tex_fetch(__curve_segments, prim);
optixSetPayload_1(optixGetAttribute_0()); /* Same as 'optixGetCurveParameter()' */
optixSetPayload_2(optixGetAttribute_1());
+ optixSetPayload_3(segment.prim);
+ optixSetPayload_5(segment.type);
+ }
+ else {
+ optixSetPayload_1(0);
+ optixSetPayload_2(0);
+ optixSetPayload_3(prim);
+ optixSetPayload_5(kernel_tex_fetch(__objects, object).primitive_type);
}
}
#ifdef __HAIR__
-ccl_device_inline void optix_intersection_curve(const uint prim, const uint type)
+ccl_device_inline void optix_intersection_curve(const int prim, const int type)
{
- const uint object = get_object_id<true>();
+ const int object = get_object_id();
+
+# ifdef __VISIBILITY_FLAG__
const uint visibility = optixGetPayload_4();
+ if ((kernel_tex_fetch(__objects, object).visibility & visibility) == 0) {
+ return;
+ }
+# endif
float3 P = optixGetObjectRayOrigin();
float3 dir = optixGetObjectRayDirection();
@@ -358,7 +438,8 @@ ccl_device_inline void optix_intersection_curve(const uint prim, const uint type
if (isect.t != FLT_MAX)
isect.t *= len;
- if (curve_intersect(NULL, &isect, P, dir, isect.t, visibility, object, prim, time, type)) {
+ if (curve_intersect(NULL, &isect, P, dir, isect.t, object, prim, time, type)) {
+ static_assert(PRIMITIVE_ALL < 128, "Values >= 128 are reserved for OptiX internal use");
optixReportIntersection(isect.t / len,
type & PRIMITIVE_ALL,
__float_as_int(isect.u), /* Attribute_0 */
@@ -368,11 +449,53 @@ ccl_device_inline void optix_intersection_curve(const uint prim, const uint type
extern "C" __global__ void __intersection__curve_ribbon()
{
- const uint prim = optixGetPrimitiveIndex();
- const uint type = kernel_tex_fetch(__prim_type, prim);
-
- if (type & (PRIMITIVE_CURVE_RIBBON | PRIMITIVE_MOTION_CURVE_RIBBON)) {
+ const KernelCurveSegment segment = kernel_tex_fetch(__curve_segments, optixGetPrimitiveIndex());
+ const int prim = segment.prim;
+ const int type = segment.type;
+ if (type & PRIMITIVE_CURVE_RIBBON) {
optix_intersection_curve(prim, type);
}
}
+
+#endif
+
+#ifdef __POINTCLOUD__
+extern "C" __global__ void __intersection__point()
+{
+ const int prim = optixGetPrimitiveIndex();
+ const int object = get_object_id();
+ const int type = kernel_tex_fetch(__objects, object).primitive_type;
+
+# ifdef __VISIBILITY_FLAG__
+ const uint visibility = optixGetPayload_4();
+ if ((kernel_tex_fetch(__objects, object).visibility & visibility) == 0) {
+ return;
+ }
+# endif
+
+ float3 P = optixGetObjectRayOrigin();
+ float3 dir = optixGetObjectRayDirection();
+
+ /* The direction is not normalized by default, the point intersection routine expects that. */
+ float len;
+ dir = normalize_len(dir, &len);
+
+# ifdef __OBJECT_MOTION__
+ const float time = optixGetRayTime();
+# else
+ const float time = 0.0f;
+# endif
+
+ Intersection isect;
+ isect.t = optixGetRayTmax();
+ /* Transform maximum distance into object space. */
+ if (isect.t != FLT_MAX) {
+ isect.t *= len;
+ }
+
+ if (point_intersect(NULL, &isect, P, dir, isect.t, object, prim, time, type)) {
+ static_assert(PRIMITIVE_ALL < 128, "Values >= 128 are reserved for OptiX internal use");
+ optixReportIntersection(isect.t / len, type & PRIMITIVE_ALL);
+ }
+}
#endif
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..fb52b1cd05f
--- /dev/null
+++ b/intern/cycles/kernel/film/accumulate.h
@@ -0,0 +1,592 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 ClosureType closure_type,
+ float3 value)
+{
+ eval->diffuse = zero_float3();
+ eval->glossy = zero_float3();
+
+ if (CLOSURE_IS_BSDF_DIFFUSE(closure_type)) {
+ eval->diffuse = value;
+ }
+ else if (CLOSURE_IS_BSDF_GLOSSY(closure_type)) {
+ eval->glossy = value;
+ }
+
+ eval->sum = value;
+}
+
+ccl_device_inline void bsdf_eval_accum(ccl_private BsdfEval *eval,
+ const ClosureType closure_type,
+ float3 value)
+{
+ if (CLOSURE_IS_BSDF_DIFFUSE(closure_type)) {
+ eval->diffuse += value;
+ }
+ else if (CLOSURE_IS_BSDF_GLOSSY(closure_type)) {
+ eval->glossy += value;
+ }
+
+ eval->sum += value;
+}
+
+ccl_device_inline bool bsdf_eval_is_zero(ccl_private BsdfEval *eval)
+{
+ return is_zero(eval->sum);
+}
+
+ccl_device_inline void bsdf_eval_mul(ccl_private BsdfEval *eval, float value)
+{
+ eval->diffuse *= value;
+ eval->glossy *= value;
+ eval->sum *= value;
+}
+
+ccl_device_inline void bsdf_eval_mul3(ccl_private BsdfEval *eval, float3 value)
+{
+ eval->diffuse *= value;
+ eval->glossy *= value;
+ eval->sum *= value;
+}
+
+ccl_device_inline float3 bsdf_eval_sum(ccl_private const BsdfEval *eval)
+{
+ return eval->sum;
+}
+
+ccl_device_inline float3 bsdf_eval_pass_diffuse_weight(ccl_private const BsdfEval *eval)
+{
+ /* Ratio of diffuse weight 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->sum);
+}
+
+ccl_device_inline float3 bsdf_eval_pass_glossy_weight(ccl_private const BsdfEval *eval)
+{
+ /* Ratio of glossy weight to recover proportions for writing to render pass.
+ * We assume reflection, transmission and volume scatter to be exclusive. */
+ return safe_divide_float3_float3(eval->glossy, eval->sum);
+}
+
+/* --------------------------------------------------------------------
+ * 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,
+ int sample_offset)
+{
+ 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(
+ (ccl_global uint *)(buffer) + kernel_data.film.pass_sample_count, 1) +
+ sample_offset;
+}
+
+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 (kernel_data.kernel_features & KERNEL_FEATURE_LIGHT_PASSES) {
+ if (path_flag & PATH_RAY_SURFACE_PASS) {
+ /* Indirectly visible through reflection. */
+ const float3 diffuse_weight = INTEGRATOR_STATE(state, path, pass_diffuse_weight);
+ const float3 glossy_weight = INTEGRATOR_STATE(state, path, pass_glossy_weight);
+
+ /* Glossy */
+ const int glossy_pass_offset = ((INTEGRATOR_STATE(state, path, bounce) == 1) ?
+ kernel_data.film.pass_glossy_direct :
+ kernel_data.film.pass_glossy_indirect);
+ if (glossy_pass_offset != PASS_UNUSED) {
+ kernel_write_pass_float3(buffer + glossy_pass_offset, glossy_weight * contribution);
+ }
+
+ /* Transmission */
+ const int transmission_pass_offset = ((INTEGRATOR_STATE(state, path, bounce) == 1) ?
+ kernel_data.film.pass_transmission_direct :
+ kernel_data.film.pass_transmission_indirect);
+
+ if (transmission_pass_offset != PASS_UNUSED) {
+ /* Transmission is what remains if not diffuse and glossy, not stored explicitly to save
+ * GPU memory. */
+ const float3 transmission_weight = one_float3() - diffuse_weight - glossy_weight;
+ kernel_write_pass_float3(buffer + transmission_pass_offset,
+ transmission_weight * 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 *= diffuse_weight;
+ }
+ }
+ 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);
+
+ if (kernel_data.kernel_features & KERNEL_FEATURE_LIGHT_PASSES) {
+ int pass_offset = PASS_UNUSED;
+
+ if (path_flag & PATH_RAY_SURFACE_PASS) {
+ /* Indirectly visible through reflection. */
+ const float3 diffuse_weight = INTEGRATOR_STATE(state, shadow_path, pass_diffuse_weight);
+ const float3 glossy_weight = INTEGRATOR_STATE(state, shadow_path, pass_glossy_weight);
+
+ /* Glossy */
+ const int glossy_pass_offset = ((INTEGRATOR_STATE(state, shadow_path, bounce) == 0) ?
+ kernel_data.film.pass_glossy_direct :
+ kernel_data.film.pass_glossy_indirect);
+ if (glossy_pass_offset != PASS_UNUSED) {
+ kernel_write_pass_float3(buffer + glossy_pass_offset, glossy_weight * contribution);
+ }
+
+ /* Transmission */
+ const int transmission_pass_offset = ((INTEGRATOR_STATE(state, shadow_path, bounce) == 0) ?
+ kernel_data.film.pass_transmission_direct :
+ kernel_data.film.pass_transmission_indirect);
+
+ if (transmission_pass_offset != PASS_UNUSED) {
+ /* Transmission is what remains if not diffuse and glossy, not stored explicitly to save
+ * GPU memory. */
+ const float3 transmission_weight = one_float3() - diffuse_weight - glossy_weight;
+ kernel_write_pass_float3(buffer + transmission_pass_offset,
+ transmission_weight * 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 *= diffuse_weight;
+ }
+ }
+ 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_TRANSPARENT_BACKGROUND)) {
+ 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 = float3(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 L,
+ ccl_global float *ccl_restrict render_buffer)
+{
+ float3 contribution = 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/film/id_passes.h b/intern/cycles/kernel/film/id_passes.h
new file mode 100644
index 00000000000..d5b8c90a828
--- /dev/null
+++ b/intern/cycles/kernel/film/id_passes.h
@@ -0,0 +1,106 @@
+/*
+ * 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
+
+CCL_NAMESPACE_BEGIN
+
+/* Element of ID pass stored in the render buffers.
+ * It is `float2` semantically, but it must be unaligned since the offset of ID passes in the
+ * render buffers might not meet expected by compiler alignment. */
+typedef struct IDPassBufferElement {
+ float x;
+ float y;
+} IDPassBufferElement;
+
+ccl_device_inline void kernel_write_id_slots(ccl_global float *buffer,
+ int num_slots,
+ float id,
+ float weight)
+{
+ kernel_assert(id != ID_NONE);
+ if (weight == 0.0f) {
+ return;
+ }
+
+ for (int slot = 0; slot < num_slots; slot++) {
+ ccl_global IDPassBufferElement *id_buffer = (ccl_global IDPassBufferElement *)buffer;
+#ifdef __ATOMIC_PASS_WRITE__
+ /* If the loop reaches an empty slot, the ID isn't in any slot yet - so add it! */
+ if (id_buffer[slot].x == ID_NONE) {
+ /* Use an atomic to claim this slot.
+ * If a different thread got here first, try again from this slot on. */
+ float old_id = atomic_compare_and_swap_float(buffer + slot * 2, ID_NONE, id);
+ if (old_id != ID_NONE && old_id != id) {
+ continue;
+ }
+ atomic_add_and_fetch_float(buffer + slot * 2 + 1, weight);
+ break;
+ }
+ /* If there already is a slot for that ID, add the weight.
+ * If no slot was found, add it to the last. */
+ else if (id_buffer[slot].x == id || slot == num_slots - 1) {
+ atomic_add_and_fetch_float(buffer + slot * 2 + 1, weight);
+ break;
+ }
+#else /* __ATOMIC_PASS_WRITE__ */
+ /* If the loop reaches an empty slot, the ID isn't in any slot yet - so add it! */
+ if (id_buffer[slot].x == ID_NONE) {
+ id_buffer[slot].x = id;
+ id_buffer[slot].y = weight;
+ break;
+ }
+ /* If there already is a slot for that ID, add the weight.
+ * If no slot was found, add it to the last. */
+ else if (id_buffer[slot].x == id || slot == num_slots - 1) {
+ id_buffer[slot].y += weight;
+ break;
+ }
+#endif /* __ATOMIC_PASS_WRITE__ */
+ }
+}
+
+ccl_device_inline void kernel_sort_id_slots(ccl_global float *buffer, int num_slots)
+{
+ ccl_global IDPassBufferElement *id_buffer = (ccl_global IDPassBufferElement *)buffer;
+ for (int slot = 1; slot < num_slots; ++slot) {
+ if (id_buffer[slot].x == ID_NONE) {
+ return;
+ }
+ /* Since we're dealing with a tiny number of elements, insertion sort should be fine. */
+ int i = slot;
+ while (i > 0 && id_buffer[i].y > id_buffer[i - 1].y) {
+ const IDPassBufferElement swap = id_buffer[i];
+ id_buffer[i] = id_buffer[i - 1];
+ id_buffer[i - 1] = swap;
+ --i;
+ }
+ }
+}
+
+/* post-sorting for Cryptomatte */
+ccl_device_inline void kernel_cryptomatte_post(KernelGlobals kg,
+ ccl_global float *render_buffer,
+ int pixel_index)
+{
+ const int pass_stride = kernel_data.film.pass_stride;
+ const uint64_t render_buffer_offset = (uint64_t)pixel_index * pass_stride;
+ ccl_global float *cryptomatte_buffer = render_buffer + render_buffer_offset +
+ kernel_data.film.pass_cryptomatte;
+ kernel_sort_id_slots(cryptomatte_buffer, 2 * kernel_data.film.cryptomatte_depth);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/film/passes.h b/intern/cycles/kernel/film/passes.h
new file mode 100644
index 00000000000..698eae29767
--- /dev/null
+++ b/intern/cycles/kernel/film/passes.h
@@ -0,0 +1,316 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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);
+ }
+ else if (sc->type == CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID) {
+ /* BSSRDF already accounts for weight, retro-reflection would double up. */
+ ccl_private const PrincipledDiffuseBsdf *bsdf = (ccl_private const PrincipledDiffuseBsdf *)
+ sc;
+ if (bsdf->components == PRINCIPLED_DIFFUSE_RETRO_REFLECTION) {
+ continue;
+ }
+ }
+
+ 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__ */
+
+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_TRANSPARENT_BACKGROUND)) {
+ 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..ba895fd8909
--- /dev/null
+++ b/intern/cycles/kernel/film/read.h
@@ -0,0 +1,547 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+ /* Optional alpha channel. */
+ if (kfilm_convert->num_components >= 4) {
+ if (kfilm_convert->pass_combined != PASS_UNUSED) {
+ float scale, scale_exposure;
+ film_get_scale_and_scale_exposure(kfilm_convert, buffer, &scale, &scale_exposure);
+
+ ccl_global const float *in_combined = buffer + kfilm_convert->pass_combined;
+ const float alpha = in_combined[3] * scale;
+ pixel[3] = film_transparency_to_alpha(alpha);
+ }
+ else {
+ pixel[3] = 1.0f;
+ }
+ }
+}
+
+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 - saturatef(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/attribute.h b/intern/cycles/kernel/geom/attribute.h
new file mode 100644
index 00000000000..8b3524beb5d
--- /dev/null
+++ b/intern/cycles/kernel/geom/attribute.h
@@ -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.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/* Attributes
+ *
+ * We support an arbitrary number of attributes on various mesh elements.
+ * On vertices, triangles, curve keys, curves, meshes and volume grids.
+ * Most of the code for attribute reading is in the primitive files.
+ *
+ * Lookup of attributes is different between OSL and SVM, as OSL is ustring
+ * based while for SVM we use integer ids. */
+
+/* Patch index for triangle, -1 if not subdivision triangle */
+
+ccl_device_inline uint subd_triangle_patch(KernelGlobals kg, ccl_private const ShaderData *sd)
+{
+ return (sd->prim != PRIM_NONE) ? kernel_tex_fetch(__tri_patch, sd->prim) : ~0;
+}
+
+ccl_device_inline uint attribute_primitive_type(KernelGlobals kg, ccl_private const ShaderData *sd)
+{
+ if ((sd->type & PRIMITIVE_TRIANGLE) && subd_triangle_patch(kg, sd) != ~0) {
+ return ATTR_PRIM_SUBD;
+ }
+ else {
+ return ATTR_PRIM_GEOMETRY;
+ }
+}
+
+ccl_device_inline AttributeDescriptor attribute_not_found()
+{
+ const AttributeDescriptor desc = {
+ ATTR_ELEMENT_NONE, (NodeAttributeType)0, 0, ATTR_STD_NOT_FOUND};
+ return desc;
+}
+
+/* Find attribute based on ID */
+
+ccl_device_inline uint object_attribute_map_offset(KernelGlobals kg, int object)
+{
+ return kernel_tex_fetch(__objects, object).attribute_map_offset;
+}
+
+ccl_device_inline AttributeDescriptor find_attribute(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ uint id)
+{
+ if (sd->object == OBJECT_NONE) {
+ return attribute_not_found();
+ }
+
+ /* for SVM, find attribute by unique id */
+ uint attr_offset = object_attribute_map_offset(kg, sd->object);
+ attr_offset += attribute_primitive_type(kg, sd);
+ uint4 attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
+
+ while (attr_map.x != id) {
+ if (UNLIKELY(attr_map.x == ATTR_STD_NONE)) {
+ if (UNLIKELY(attr_map.y == 0)) {
+ return attribute_not_found();
+ }
+ else {
+ /* Chain jump to a different part of the table. */
+ attr_offset = attr_map.z;
+ }
+ }
+ else {
+ attr_offset += ATTR_PRIM_TYPES;
+ }
+ attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
+ }
+
+ AttributeDescriptor desc;
+ desc.element = (AttributeElement)attr_map.y;
+
+ if (sd->prim == PRIM_NONE && desc.element != ATTR_ELEMENT_MESH &&
+ desc.element != ATTR_ELEMENT_VOXEL && desc.element != ATTR_ELEMENT_OBJECT) {
+ return attribute_not_found();
+ }
+
+ /* return result */
+ desc.offset = (attr_map.y == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : (int)attr_map.z;
+ desc.type = (NodeAttributeType)(attr_map.w & 0xff);
+ desc.flags = (AttributeFlag)(attr_map.w >> 8);
+
+ return desc;
+}
+
+/* Transform matrix attribute on meshes */
+
+ccl_device Transform primitive_attribute_matrix(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ const AttributeDescriptor desc)
+{
+ Transform tfm;
+
+ tfm.x = kernel_tex_fetch(__attributes_float4, desc.offset + 0);
+ tfm.y = kernel_tex_fetch(__attributes_float4, desc.offset + 1);
+ tfm.z = kernel_tex_fetch(__attributes_float4, desc.offset + 2);
+
+ return tfm;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/geom/curve.h b/intern/cycles/kernel/geom/curve.h
new file mode 100644
index 00000000000..48ee8226e89
--- /dev/null
+++ b/intern/cycles/kernel/geom/curve.h
@@ -0,0 +1,340 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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
+
+/* Curve Primitive
+ *
+ * Curve primitive for rendering hair and fur. These can be render as flat
+ * ribbons or curves with actual thickness. The curve can also be rendered as
+ * line segments rather than curves for better performance.
+ */
+
+#ifdef __HAIR__
+
+/* Reading attributes on various curve elements */
+
+ccl_device float curve_attribute_float(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ const AttributeDescriptor desc,
+ ccl_private float *dx,
+ ccl_private float *dy)
+{
+ if (desc.element & (ATTR_ELEMENT_CURVE_KEY | ATTR_ELEMENT_CURVE_KEY_MOTION)) {
+ KernelCurve curve = kernel_tex_fetch(__curves, sd->prim);
+ int k0 = curve.first_key + PRIMITIVE_UNPACK_SEGMENT(sd->type);
+ int k1 = k0 + 1;
+
+ float f0 = kernel_tex_fetch(__attributes_float, desc.offset + k0);
+ float f1 = kernel_tex_fetch(__attributes_float, desc.offset + k1);
+
+# ifdef __RAY_DIFFERENTIALS__
+ if (dx)
+ *dx = sd->du.dx * (f1 - f0);
+ if (dy)
+ *dy = 0.0f;
+# endif
+
+ return (1.0f - sd->u) * f0 + sd->u * f1;
+ }
+ else {
+# ifdef __RAY_DIFFERENTIALS__
+ if (dx)
+ *dx = 0.0f;
+ if (dy)
+ *dy = 0.0f;
+# endif
+
+ if (desc.element & (ATTR_ELEMENT_CURVE | ATTR_ELEMENT_OBJECT | ATTR_ELEMENT_MESH)) {
+ const int offset = (desc.element == ATTR_ELEMENT_CURVE) ? desc.offset + sd->prim :
+ desc.offset;
+ return kernel_tex_fetch(__attributes_float, offset);
+ }
+ else {
+ return 0.0f;
+ }
+ }
+}
+
+ccl_device float2 curve_attribute_float2(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ const AttributeDescriptor desc,
+ ccl_private float2 *dx,
+ ccl_private float2 *dy)
+{
+ if (desc.element & (ATTR_ELEMENT_CURVE_KEY | ATTR_ELEMENT_CURVE_KEY_MOTION)) {
+ KernelCurve curve = kernel_tex_fetch(__curves, sd->prim);
+ int k0 = curve.first_key + PRIMITIVE_UNPACK_SEGMENT(sd->type);
+ int k1 = k0 + 1;
+
+ float2 f0 = kernel_tex_fetch(__attributes_float2, desc.offset + k0);
+ float2 f1 = kernel_tex_fetch(__attributes_float2, desc.offset + k1);
+
+# ifdef __RAY_DIFFERENTIALS__
+ if (dx)
+ *dx = sd->du.dx * (f1 - f0);
+ if (dy)
+ *dy = make_float2(0.0f, 0.0f);
+# endif
+
+ return (1.0f - sd->u) * f0 + sd->u * f1;
+ }
+ else {
+ /* idea: we can't derive any useful differentials here, but for tiled
+ * mipmap image caching it would be useful to avoid reading the highest
+ * detail level always. maybe a derivative based on the hair density
+ * could be computed somehow? */
+# ifdef __RAY_DIFFERENTIALS__
+ if (dx)
+ *dx = make_float2(0.0f, 0.0f);
+ if (dy)
+ *dy = make_float2(0.0f, 0.0f);
+# endif
+
+ if (desc.element & (ATTR_ELEMENT_CURVE | ATTR_ELEMENT_OBJECT | ATTR_ELEMENT_MESH)) {
+ const int offset = (desc.element == ATTR_ELEMENT_CURVE) ? desc.offset + sd->prim :
+ desc.offset;
+ return kernel_tex_fetch(__attributes_float2, offset);
+ }
+ else {
+ return make_float2(0.0f, 0.0f);
+ }
+ }
+}
+
+ccl_device float3 curve_attribute_float3(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ const AttributeDescriptor desc,
+ ccl_private float3 *dx,
+ ccl_private float3 *dy)
+{
+ if (desc.element & (ATTR_ELEMENT_CURVE_KEY | ATTR_ELEMENT_CURVE_KEY_MOTION)) {
+ KernelCurve curve = kernel_tex_fetch(__curves, sd->prim);
+ int k0 = curve.first_key + PRIMITIVE_UNPACK_SEGMENT(sd->type);
+ int k1 = k0 + 1;
+
+ float3 f0 = kernel_tex_fetch(__attributes_float3, desc.offset + k0);
+ float3 f1 = kernel_tex_fetch(__attributes_float3, desc.offset + k1);
+
+# ifdef __RAY_DIFFERENTIALS__
+ if (dx)
+ *dx = sd->du.dx * (f1 - f0);
+ if (dy)
+ *dy = make_float3(0.0f, 0.0f, 0.0f);
+# endif
+
+ return (1.0f - sd->u) * f0 + sd->u * f1;
+ }
+ else {
+# ifdef __RAY_DIFFERENTIALS__
+ if (dx)
+ *dx = make_float3(0.0f, 0.0f, 0.0f);
+ if (dy)
+ *dy = make_float3(0.0f, 0.0f, 0.0f);
+# endif
+
+ if (desc.element & (ATTR_ELEMENT_CURVE | ATTR_ELEMENT_OBJECT | ATTR_ELEMENT_MESH)) {
+ const int offset = (desc.element == ATTR_ELEMENT_CURVE) ? desc.offset + sd->prim :
+ desc.offset;
+ return kernel_tex_fetch(__attributes_float3, offset);
+ }
+ else {
+ return make_float3(0.0f, 0.0f, 0.0f);
+ }
+ }
+}
+
+ccl_device float4 curve_attribute_float4(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ const AttributeDescriptor desc,
+ ccl_private float4 *dx,
+ ccl_private float4 *dy)
+{
+ if (desc.element & (ATTR_ELEMENT_CURVE_KEY | ATTR_ELEMENT_CURVE_KEY_MOTION)) {
+ KernelCurve curve = kernel_tex_fetch(__curves, sd->prim);
+ int k0 = curve.first_key + PRIMITIVE_UNPACK_SEGMENT(sd->type);
+ int k1 = k0 + 1;
+
+ float4 f0 = kernel_tex_fetch(__attributes_float4, desc.offset + k0);
+ float4 f1 = kernel_tex_fetch(__attributes_float4, desc.offset + k1);
+
+# ifdef __RAY_DIFFERENTIALS__
+ if (dx)
+ *dx = sd->du.dx * (f1 - f0);
+ if (dy)
+ *dy = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+# endif
+
+ return (1.0f - sd->u) * f0 + sd->u * f1;
+ }
+ else {
+# ifdef __RAY_DIFFERENTIALS__
+ 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);
+# endif
+
+ if (desc.element & (ATTR_ELEMENT_CURVE | ATTR_ELEMENT_OBJECT | ATTR_ELEMENT_MESH)) {
+ const int offset = (desc.element == ATTR_ELEMENT_CURVE) ? desc.offset + sd->prim :
+ desc.offset;
+ return kernel_tex_fetch(__attributes_float4, offset);
+ }
+ else {
+ return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ }
+ }
+}
+
+/* Curve thickness */
+
+ccl_device float curve_thickness(KernelGlobals kg, ccl_private const ShaderData *sd)
+{
+ float r = 0.0f;
+
+ if (sd->type & PRIMITIVE_CURVE) {
+ KernelCurve curve = kernel_tex_fetch(__curves, sd->prim);
+ int k0 = curve.first_key + PRIMITIVE_UNPACK_SEGMENT(sd->type);
+ int k1 = k0 + 1;
+
+ float4 P_curve[2];
+
+ if (!(sd->type & PRIMITIVE_MOTION)) {
+ P_curve[0] = kernel_tex_fetch(__curve_keys, k0);
+ P_curve[1] = kernel_tex_fetch(__curve_keys, k1);
+ }
+ else {
+ motion_curve_keys_linear(kg, sd->object, sd->prim, sd->time, k0, k1, P_curve);
+ }
+
+ r = (P_curve[1].w - P_curve[0].w) * sd->u + P_curve[0].w;
+ }
+
+ return r * 2.0f;
+}
+
+/* Curve random */
+
+ccl_device float curve_random(KernelGlobals kg, ccl_private const ShaderData *sd)
+{
+ if (sd->type & PRIMITIVE_CURVE) {
+ const AttributeDescriptor desc = find_attribute(kg, sd, ATTR_STD_CURVE_RANDOM);
+ return (desc.offset != ATTR_STD_NOT_FOUND) ? curve_attribute_float(kg, sd, desc, NULL, NULL) :
+ 0.0f;
+ }
+ return 0.0f;
+}
+
+/* Curve location for motion pass, linear interpolation between keys and
+ * ignoring radius because we do the same for the motion keys */
+
+ccl_device float3 curve_motion_center_location(KernelGlobals kg, ccl_private const ShaderData *sd)
+{
+ KernelCurve curve = kernel_tex_fetch(__curves, sd->prim);
+ int k0 = curve.first_key + PRIMITIVE_UNPACK_SEGMENT(sd->type);
+ int k1 = k0 + 1;
+
+ float4 P_curve[2];
+
+ P_curve[0] = kernel_tex_fetch(__curve_keys, k0);
+ P_curve[1] = kernel_tex_fetch(__curve_keys, k1);
+
+ return float4_to_float3(P_curve[1]) * sd->u + float4_to_float3(P_curve[0]) * (1.0f - sd->u);
+}
+
+/* Curve tangent normal */
+
+ccl_device float3 curve_tangent_normal(KernelGlobals kg, ccl_private const ShaderData *sd)
+{
+ float3 tgN = make_float3(0.0f, 0.0f, 0.0f);
+
+ if (sd->type & PRIMITIVE_CURVE) {
+
+ tgN = -(-sd->I - sd->dPdu * (dot(sd->dPdu, -sd->I) / len_squared(sd->dPdu)));
+ tgN = normalize(tgN);
+
+ /* need to find suitable scaled gd for corrected normal */
+# if 0
+ tgN = normalize(tgN - gd * sd->dPdu);
+# endif
+ }
+
+ return tgN;
+}
+
+/* Curve bounds utility function */
+
+ccl_device_inline void curvebounds(ccl_private float *lower,
+ ccl_private float *upper,
+ ccl_private float *extremta,
+ ccl_private float *extrema,
+ ccl_private float *extremtb,
+ ccl_private float *extremb,
+ float p0,
+ float p1,
+ float p2,
+ float p3)
+{
+ float halfdiscroot = (p2 * p2 - 3 * p3 * p1);
+ float ta = -1.0f;
+ float tb = -1.0f;
+
+ *extremta = -1.0f;
+ *extremtb = -1.0f;
+ *upper = p0;
+ *lower = (p0 + p1) + (p2 + p3);
+ *extrema = *upper;
+ *extremb = *lower;
+
+ if (*lower >= *upper) {
+ *upper = *lower;
+ *lower = p0;
+ }
+
+ if (halfdiscroot >= 0) {
+ float inv3p3 = (1.0f / 3.0f) / p3;
+ halfdiscroot = sqrtf(halfdiscroot);
+ ta = (-p2 - halfdiscroot) * inv3p3;
+ tb = (-p2 + halfdiscroot) * inv3p3;
+ }
+
+ float t2;
+ float t3;
+
+ if (ta > 0.0f && ta < 1.0f) {
+ t2 = ta * ta;
+ t3 = t2 * ta;
+ *extremta = ta;
+ *extrema = p3 * t3 + p2 * t2 + p1 * ta + p0;
+
+ *upper = fmaxf(*extrema, *upper);
+ *lower = fminf(*extrema, *lower);
+ }
+
+ if (tb > 0.0f && tb < 1.0f) {
+ t2 = tb * tb;
+ t3 = t2 * tb;
+ *extremtb = tb;
+ *extremb = p3 * t3 + p2 * t2 + p1 * tb + p0;
+
+ *upper = fmaxf(*extremb, *upper);
+ *lower = fminf(*extremb, *lower);
+ }
+}
+
+#endif /* __HAIR__ */
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/geom/curve_intersect.h b/intern/cycles/kernel/geom/curve_intersect.h
new file mode 100644
index 00000000000..2081eeb3eac
--- /dev/null
+++ b/intern/cycles/kernel/geom/curve_intersect.h
@@ -0,0 +1,771 @@
+/*
+ * Copyright 2009-2020 Intel Corporation. Adapted from Embree with
+ * with modifications.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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
+
+/* Curve primitive intersection functions.
+ *
+ * The code here was adapted from curve_intersector_sweep.h in Embree, to get
+ * an exact match between Embree CPU ray-tracing and our GPU ray-tracing. */
+
+#define CURVE_NUM_BEZIER_SUBDIVISIONS 3
+#define CURVE_NUM_BEZIER_SUBDIVISIONS_UNSTABLE (CURVE_NUM_BEZIER_SUBDIVISIONS + 1)
+#define CURVE_NUM_BEZIER_STEPS 2
+#define CURVE_NUM_JACOBIAN_ITERATIONS 5
+
+#ifdef __HAIR__
+
+/* Catmull-rom curve evaluation. */
+
+ccl_device_inline float4 catmull_rom_basis_eval(const float4 curve[4], float u)
+{
+ const float t = u;
+ const float s = 1.0f - u;
+ const float n0 = -t * s * s;
+ const float n1 = 2.0f + t * t * (3.0f * t - 5.0f);
+ const float n2 = 2.0f + s * s * (3.0f * s - 5.0f);
+ const float n3 = -s * t * t;
+ return 0.5f * (curve[0] * n0 + curve[1] * n1 + curve[2] * n2 + curve[3] * n3);
+}
+
+ccl_device_inline float4 catmull_rom_basis_derivative(const float4 curve[4], float u)
+{
+ const float t = u;
+ const float s = 1.0f - u;
+ const float n0 = -s * s + 2.0f * s * t;
+ const float n1 = 2.0f * t * (3.0f * t - 5.0f) + 3.0f * t * t;
+ const float n2 = 2.0f * s * (3.0f * t + 2.0f) - 3.0f * s * s;
+ const float n3 = -2.0f * s * t + t * t;
+ return 0.5f * (curve[0] * n0 + curve[1] * n1 + curve[2] * n2 + curve[3] * n3);
+}
+
+ccl_device_inline float4 catmull_rom_basis_derivative2(const float4 curve[4], float u)
+{
+
+ const float t = u;
+ const float n0 = -3.0f * t + 2.0f;
+ const float n1 = 9.0f * t - 5.0f;
+ const float n2 = -9.0f * t + 4.0f;
+ const float n3 = 3.0f * t - 1.0f;
+ return (curve[0] * n0 + curve[1] * n1 + curve[2] * n2 + curve[3] * n3);
+}
+
+/* Thick Curve */
+
+ccl_device_inline float3 dnormalize(const float3 p, const float3 dp)
+{
+ const float pp = dot(p, p);
+ const float pdp = dot(p, dp);
+ return (pp * dp - pdp * p) / (pp * sqrtf(pp));
+}
+
+ccl_device_inline float sqr_point_to_line_distance(const float3 PmQ0, const float3 Q1mQ0)
+{
+ const float3 N = cross(PmQ0, Q1mQ0);
+ const float3 D = Q1mQ0;
+ return dot(N, N) / dot(D, D);
+}
+
+ccl_device_inline bool cylinder_intersect(const float3 cylinder_start,
+ const float3 cylinder_end,
+ const float cylinder_radius,
+ const float3 ray_dir,
+ ccl_private float2 *t_o,
+ ccl_private float *u0_o,
+ ccl_private float3 *Ng0_o,
+ ccl_private float *u1_o,
+ ccl_private float3 *Ng1_o)
+{
+ /* Calculate quadratic equation to solve. */
+ const float rl = 1.0f / len(cylinder_end - cylinder_start);
+ const float3 P0 = cylinder_start, dP = (cylinder_end - cylinder_start) * rl;
+ const float3 O = -P0, dO = ray_dir;
+
+ const float dOdO = dot(dO, dO);
+ const float OdO = dot(dO, O);
+ const float OO = dot(O, O);
+ const float dOz = dot(dP, dO);
+ const float Oz = dot(dP, O);
+
+ const float A = dOdO - sqr(dOz);
+ const float B = 2.0f * (OdO - dOz * Oz);
+ const float C = OO - sqr(Oz) - sqr(cylinder_radius);
+
+ /* We miss the cylinder if determinant is smaller than zero. */
+ const float D = B * B - 4.0f * A * C;
+ if (!(D >= 0.0f)) {
+ *t_o = make_float2(FLT_MAX, -FLT_MAX);
+ return false;
+ }
+
+ /* Special case for rays that are parallel to the cylinder. */
+ const float eps = 16.0f * FLT_EPSILON * max(fabsf(dOdO), fabsf(sqr(dOz)));
+ if (fabsf(A) < eps) {
+ if (C <= 0.0f) {
+ *t_o = make_float2(-FLT_MAX, FLT_MAX);
+ return true;
+ }
+ else {
+ *t_o = make_float2(-FLT_MAX, FLT_MAX);
+ return false;
+ }
+ }
+
+ /* Standard case for rays that are not parallel to the cylinder. */
+ const float Q = sqrtf(D);
+ const float rcp_2A = 1.0f / (2.0f * A);
+ const float t0 = (-B - Q) * rcp_2A;
+ const float t1 = (-B + Q) * rcp_2A;
+
+ /* Calculates u and Ng for near hit. */
+ {
+ *u0_o = (t0 * dOz + Oz) * rl;
+ const float3 Pr = t0 * ray_dir;
+ const float3 Pl = (*u0_o) * (cylinder_end - cylinder_start) + cylinder_start;
+ *Ng0_o = Pr - Pl;
+ }
+
+ /* Calculates u and Ng for far hit. */
+ {
+ *u1_o = (t1 * dOz + Oz) * rl;
+ const float3 Pr = t1 * ray_dir;
+ const float3 Pl = (*u1_o) * (cylinder_end - cylinder_start) + cylinder_start;
+ *Ng1_o = Pr - Pl;
+ }
+
+ *t_o = make_float2(t0, t1);
+
+ return true;
+}
+
+ccl_device_inline float2 half_plane_intersect(const float3 P, const float3 N, const float3 ray_dir)
+{
+ const float3 O = -P;
+ const float3 D = ray_dir;
+ const float ON = dot(O, N);
+ const float DN = dot(D, N);
+ const float min_rcp_input = 1e-18f;
+ const bool eps = fabsf(DN) < min_rcp_input;
+ const float t = -ON / DN;
+ const float lower = (eps || DN < 0.0f) ? -FLT_MAX : t;
+ const float upper = (eps || DN > 0.0f) ? FLT_MAX : t;
+ return make_float2(lower, upper);
+}
+
+ccl_device bool curve_intersect_iterative(const float3 ray_dir,
+ ccl_private float *ray_tfar,
+ const float dt,
+ const float4 curve[4],
+ float u,
+ float t,
+ const bool use_backfacing,
+ ccl_private Intersection *isect)
+{
+ const float length_ray_dir = len(ray_dir);
+
+ /* Error of curve evaluations is proportional to largest coordinate. */
+ const float4 box_min = min(min(curve[0], curve[1]), min(curve[2], curve[3]));
+ const float4 box_max = max(min(curve[0], curve[1]), max(curve[2], curve[3]));
+ const float4 box_abs = max(fabs(box_min), fabs(box_max));
+ const float P_err = 16.0f * FLT_EPSILON *
+ max(box_abs.x, max(box_abs.y, max(box_abs.z, box_abs.w)));
+ const float radius_max = box_max.w;
+
+ for (int i = 0; i < CURVE_NUM_JACOBIAN_ITERATIONS; i++) {
+ const float3 Q = ray_dir * t;
+ const float3 dQdt = ray_dir;
+ const float Q_err = 16.0f * FLT_EPSILON * length_ray_dir * t;
+
+ const float4 P4 = catmull_rom_basis_eval(curve, u);
+ const float4 dPdu4 = catmull_rom_basis_derivative(curve, u);
+
+ const float3 P = float4_to_float3(P4);
+ const float3 dPdu = float4_to_float3(dPdu4);
+ const float radius = P4.w;
+ const float dradiusdu = dPdu4.w;
+
+ const float3 ddPdu = float4_to_float3(catmull_rom_basis_derivative2(curve, u));
+
+ const float3 R = Q - P;
+ const float len_R = len(R);
+ const float R_err = max(Q_err, P_err);
+ const float3 dRdu = -dPdu;
+ const float3 dRdt = dQdt;
+
+ const float3 T = normalize(dPdu);
+ const float3 dTdu = dnormalize(dPdu, ddPdu);
+ const float cos_err = P_err / len(dPdu);
+
+ const float f = dot(R, T);
+ const float f_err = len_R * P_err + R_err + cos_err * (1.0f + len_R);
+ const float dfdu = dot(dRdu, T) + dot(R, dTdu);
+ const float dfdt = dot(dRdt, T);
+
+ const float K = dot(R, R) - sqr(f);
+ const float dKdu = (dot(R, dRdu) - f * dfdu);
+ const float dKdt = (dot(R, dRdt) - f * dfdt);
+ const float rsqrt_K = inversesqrtf(K);
+
+ const float g = sqrtf(K) - radius;
+ const float g_err = R_err + f_err + 16.0f * FLT_EPSILON * radius_max;
+ const float dgdu = dKdu * rsqrt_K - dradiusdu;
+ const float dgdt = dKdt * rsqrt_K;
+
+ const float invdet = 1.0f / (dfdu * dgdt - dgdu * dfdt);
+ u -= (dgdt * f - dfdt * g) * invdet;
+ t -= (-dgdu * f + dfdu * g) * invdet;
+
+ if (fabsf(f) < f_err && fabsf(g) < g_err) {
+ t += dt;
+ if (!(0.0f <= t && t <= *ray_tfar)) {
+ return false; /* Rejects NaNs */
+ }
+ if (!(u >= 0.0f && u <= 1.0f)) {
+ return false; /* Rejects NaNs */
+ }
+
+ /* Back-face culling. */
+ const float3 R = normalize(Q - P);
+ const float3 U = dradiusdu * R + dPdu;
+ const float3 V = cross(dPdu, R);
+ const float3 Ng = cross(V, U);
+ if (!use_backfacing && dot(ray_dir, Ng) > 0.0f) {
+ return false;
+ }
+
+ /* Record intersection. */
+ *ray_tfar = t;
+ isect->t = t;
+ isect->u = u;
+ isect->v = 0.0f;
+
+ return true;
+ }
+ }
+ return false;
+}
+
+ccl_device bool curve_intersect_recursive(const float3 ray_orig,
+ const float3 ray_dir,
+ float ray_tfar,
+ float4 curve[4],
+ ccl_private Intersection *isect)
+{
+ /* Move ray closer to make intersection stable. */
+ const float3 center = float4_to_float3(0.25f * (curve[0] + curve[1] + curve[2] + curve[3]));
+ const float dt = dot(center - ray_orig, ray_dir) / dot(ray_dir, ray_dir);
+ const float3 ref = ray_orig + ray_dir * dt;
+ const float4 ref4 = make_float4(ref.x, ref.y, ref.z, 0.0f);
+ curve[0] -= ref4;
+ curve[1] -= ref4;
+ curve[2] -= ref4;
+ curve[3] -= ref4;
+
+ const bool use_backfacing = false;
+ const float step_size = 1.0f / (float)(CURVE_NUM_BEZIER_STEPS);
+
+ int depth = 0;
+
+ /* todo: optimize stack for GPU somehow? Possibly some bitflags are enough, and
+ * u0/u1 can be derived from the depth. */
+ struct {
+ float u0, u1;
+ int i;
+ } stack[CURVE_NUM_BEZIER_SUBDIVISIONS_UNSTABLE];
+
+ bool found = false;
+
+ float u0 = 0.0f;
+ float u1 = 1.0f;
+ int i = 0;
+
+ while (1) {
+ for (; i < CURVE_NUM_BEZIER_STEPS; i++) {
+ const float step = i * step_size;
+
+ /* Subdivide curve. */
+ const float dscale = (u1 - u0) * (1.0f / 3.0f) * step_size;
+ const float vu0 = mix(u0, u1, step);
+ const float vu1 = mix(u0, u1, step + step_size);
+
+ const float4 P0 = catmull_rom_basis_eval(curve, vu0);
+ const float4 dP0du = dscale * catmull_rom_basis_derivative(curve, vu0);
+ const float4 P3 = catmull_rom_basis_eval(curve, vu1);
+ const float4 dP3du = dscale * catmull_rom_basis_derivative(curve, vu1);
+
+ const float4 P1 = P0 + dP0du;
+ const float4 P2 = P3 - dP3du;
+
+ /* Calculate bounding cylinders. */
+ const float rr1 = sqr_point_to_line_distance(float4_to_float3(dP0du),
+ float4_to_float3(P3 - P0));
+ const float rr2 = sqr_point_to_line_distance(float4_to_float3(dP3du),
+ float4_to_float3(P3 - P0));
+ const float maxr12 = sqrtf(max(rr1, rr2));
+ const float one_plus_ulp = 1.0f + 2.0f * FLT_EPSILON;
+ const float one_minus_ulp = 1.0f - 2.0f * FLT_EPSILON;
+ float r_outer = max(max(P0.w, P1.w), max(P2.w, P3.w)) + maxr12;
+ float r_inner = min(min(P0.w, P1.w), min(P2.w, P3.w)) - maxr12;
+ r_outer = one_plus_ulp * r_outer;
+ r_inner = max(0.0f, one_minus_ulp * r_inner);
+ bool valid = true;
+
+ /* Intersect with outer cylinder. */
+ float2 tc_outer;
+ float u_outer0, u_outer1;
+ float3 Ng_outer0, Ng_outer1;
+ valid = cylinder_intersect(float4_to_float3(P0),
+ float4_to_float3(P3),
+ r_outer,
+ ray_dir,
+ &tc_outer,
+ &u_outer0,
+ &Ng_outer0,
+ &u_outer1,
+ &Ng_outer1);
+ if (!valid) {
+ continue;
+ }
+
+ /* Intersect with cap-planes. */
+ float2 tp = make_float2(-dt, ray_tfar - dt);
+ tp = make_float2(max(tp.x, tc_outer.x), min(tp.y, tc_outer.y));
+ const float2 h0 = half_plane_intersect(
+ float4_to_float3(P0), float4_to_float3(dP0du), ray_dir);
+ tp = make_float2(max(tp.x, h0.x), min(tp.y, h0.y));
+ const float2 h1 = half_plane_intersect(
+ float4_to_float3(P3), -float4_to_float3(dP3du), ray_dir);
+ tp = make_float2(max(tp.x, h1.x), min(tp.y, h1.y));
+ valid = tp.x <= tp.y;
+ if (!valid) {
+ continue;
+ }
+
+ /* Clamp and correct u parameter. */
+ u_outer0 = clamp(u_outer0, 0.0f, 1.0f);
+ u_outer1 = clamp(u_outer1, 0.0f, 1.0f);
+ u_outer0 = mix(u0, u1, (step + u_outer0) * (1.0f / (float)(CURVE_NUM_BEZIER_STEPS + 1)));
+ u_outer1 = mix(u0, u1, (step + u_outer1) * (1.0f / (float)(CURVE_NUM_BEZIER_STEPS + 1)));
+
+ /* Intersect with inner cylinder. */
+ float2 tc_inner;
+ float u_inner0, u_inner1;
+ float3 Ng_inner0, Ng_inner1;
+ const bool valid_inner = cylinder_intersect(float4_to_float3(P0),
+ float4_to_float3(P3),
+ r_inner,
+ ray_dir,
+ &tc_inner,
+ &u_inner0,
+ &Ng_inner0,
+ &u_inner1,
+ &Ng_inner1);
+
+ /* At the unstable area we subdivide deeper. */
+# if 0
+ const bool unstable0 = (!valid_inner) |
+ (fabsf(dot(normalize(ray_dir), normalize(Ng_inner0))) < 0.3f);
+ const bool unstable1 = (!valid_inner) |
+ (fabsf(dot(normalize(ray_dir), normalize(Ng_inner1))) < 0.3f);
+# else
+ /* On the GPU appears to be a little faster if always enabled. */
+ (void)valid_inner;
+
+ const bool unstable0 = true;
+ const bool unstable1 = true;
+# endif
+
+ /* Subtract the inner interval from the current hit interval. */
+ float2 tp0 = make_float2(tp.x, min(tp.y, tc_inner.x));
+ float2 tp1 = make_float2(max(tp.x, tc_inner.y), tp.y);
+ bool valid0 = valid && (tp0.x <= tp0.y);
+ bool valid1 = valid && (tp1.x <= tp1.y);
+ if (!(valid0 || valid1)) {
+ continue;
+ }
+
+ /* Process one or two hits. */
+ bool recurse = false;
+ if (valid0) {
+ const int termDepth = unstable0 ? CURVE_NUM_BEZIER_SUBDIVISIONS_UNSTABLE :
+ CURVE_NUM_BEZIER_SUBDIVISIONS;
+ if (depth >= termDepth) {
+ found |= curve_intersect_iterative(
+ ray_dir, &ray_tfar, dt, curve, u_outer0, tp0.x, use_backfacing, isect);
+ }
+ else {
+ recurse = true;
+ }
+ }
+
+ if (valid1 && (tp1.x + dt <= ray_tfar)) {
+ const int termDepth = unstable1 ? CURVE_NUM_BEZIER_SUBDIVISIONS_UNSTABLE :
+ CURVE_NUM_BEZIER_SUBDIVISIONS;
+ if (depth >= termDepth) {
+ found |= curve_intersect_iterative(
+ ray_dir, &ray_tfar, dt, curve, u_outer1, tp1.y, use_backfacing, isect);
+ }
+ else {
+ recurse = true;
+ }
+ }
+
+ if (recurse) {
+ stack[depth].u0 = u0;
+ stack[depth].u1 = u1;
+ stack[depth].i = i + 1;
+ depth++;
+
+ u0 = vu0;
+ u1 = vu1;
+ i = -1;
+ }
+ }
+
+ if (depth > 0) {
+ depth--;
+ u0 = stack[depth].u0;
+ u1 = stack[depth].u1;
+ i = stack[depth].i;
+ }
+ else {
+ break;
+ }
+ }
+
+ return found;
+}
+
+/* Ribbons */
+
+ccl_device_inline bool cylinder_culling_test(const float2 p1, const float2 p2, const float r)
+{
+ /* Performs culling against a cylinder. */
+ const float2 dp = p2 - p1;
+ const float num = dp.x * p1.y - dp.y * p1.x;
+ const float den2 = dot(dp, dp);
+ return num * num <= r * r * den2;
+}
+
+/**
+ * Intersects a ray with a quad with back-face culling
+ * enabled. The quad v0,v1,v2,v3 is split into two triangles
+ * v0,v1,v3 and v2,v3,v1. The edge v1,v2 decides which of the two
+ * triangles gets intersected.
+ */
+ccl_device_inline bool ribbon_intersect_quad(const float ray_tfar,
+ const float3 quad_v0,
+ const float3 quad_v1,
+ const float3 quad_v2,
+ const float3 quad_v3,
+ ccl_private float *u_o,
+ ccl_private float *v_o,
+ ccl_private float *t_o)
+{
+ /* Calculate vertices relative to ray origin? */
+ const float3 O = make_float3(0.0f, 0.0f, 0.0f);
+ const float3 D = make_float3(0.0f, 0.0f, 1.0f);
+ const float3 va = quad_v0 - O;
+ const float3 vb = quad_v1 - O;
+ const float3 vc = quad_v2 - O;
+ const float3 vd = quad_v3 - O;
+
+ const float3 edb = vb - vd;
+ const float WW = dot(cross(vd, edb), D);
+ const float3 v0 = (WW <= 0.0f) ? va : vc;
+ const float3 v1 = (WW <= 0.0f) ? vb : vd;
+ const float3 v2 = (WW <= 0.0f) ? vd : vb;
+
+ /* Calculate edges? */
+ const float3 e0 = v2 - v0;
+ const float3 e1 = v0 - v1;
+
+ /* perform edge tests */
+ const float U = dot(cross(v0, e0), D);
+ const float V = dot(cross(v1, e1), D);
+ if (!(max(U, V) <= 0.0f)) {
+ return false;
+ }
+
+ /* Calculate geometry normal and denominator? */
+ const float3 Ng = cross(e1, e0);
+ const float den = dot(Ng, D);
+ const float rcpDen = 1.0f / den;
+
+ /* Perform depth test? */
+ const float t = rcpDen * dot(v0, Ng);
+ if (!(0.0f <= t && t <= ray_tfar)) {
+ return false;
+ }
+
+ /* Avoid division by 0? */
+ if (!(den != 0.0f)) {
+ return false;
+ }
+
+ /* Update hit information? */
+ *t_o = t;
+ *u_o = U * rcpDen;
+ *v_o = V * rcpDen;
+ *u_o = (WW <= 0.0f) ? *u_o : 1.0f - *u_o;
+ *v_o = (WW <= 0.0f) ? *v_o : 1.0f - *v_o;
+ return true;
+}
+
+ccl_device_inline void ribbon_ray_space(const float3 ray_dir, float3 ray_space[3])
+{
+ const float3 dx0 = make_float3(0, ray_dir.z, -ray_dir.y);
+ const float3 dx1 = make_float3(-ray_dir.z, 0, ray_dir.x);
+ ray_space[0] = normalize(dot(dx0, dx0) > dot(dx1, dx1) ? dx0 : dx1);
+ ray_space[1] = normalize(cross(ray_dir, ray_space[0]));
+ ray_space[2] = ray_dir;
+}
+
+ccl_device_inline float4 ribbon_to_ray_space(const float3 ray_space[3],
+ const float3 ray_org,
+ const float4 P4)
+{
+ float3 P = float4_to_float3(P4) - ray_org;
+ return make_float4(dot(ray_space[0], P), dot(ray_space[1], P), dot(ray_space[2], P), P4.w);
+}
+
+ccl_device_inline bool ribbon_intersect(const float3 ray_org,
+ const float3 ray_dir,
+ float ray_tfar,
+ const int N,
+ float4 curve[4],
+ ccl_private Intersection *isect)
+{
+ /* Transform control points into ray space. */
+ float3 ray_space[3];
+ ribbon_ray_space(ray_dir, ray_space);
+
+ curve[0] = ribbon_to_ray_space(ray_space, ray_org, curve[0]);
+ curve[1] = ribbon_to_ray_space(ray_space, ray_org, curve[1]);
+ curve[2] = ribbon_to_ray_space(ray_space, ray_org, curve[2]);
+ curve[3] = ribbon_to_ray_space(ray_space, ray_org, curve[3]);
+
+ const float4 mx = max(max(fabs(curve[0]), fabs(curve[1])), max(fabs(curve[2]), fabs(curve[3])));
+ const float eps = 4.0f * FLT_EPSILON * max(max(mx.x, mx.y), max(mx.z, mx.w));
+ const float step_size = 1.0f / (float)N;
+
+ /* Evaluate first point and radius scaled normal direction. */
+ float4 p0 = catmull_rom_basis_eval(curve, 0.0f);
+ float3 dp0dt = float4_to_float3(catmull_rom_basis_derivative(curve, 0.0f));
+ if (max3(fabs(dp0dt)) < eps) {
+ const float4 p1 = catmull_rom_basis_eval(curve, step_size);
+ dp0dt = float4_to_float3(p1 - p0);
+ }
+ float3 wn0 = normalize(make_float3(dp0dt.y, -dp0dt.x, 0.0f)) * p0.w;
+
+ /* Evaluate the bezier curve. */
+ for (int i = 0; i < N; i++) {
+ const float u = i * step_size;
+ const float4 p1 = catmull_rom_basis_eval(curve, u + step_size);
+ const bool valid = cylinder_culling_test(
+ make_float2(p0.x, p0.y), make_float2(p1.x, p1.y), max(p0.w, p1.w));
+
+ /* Evaluate next point. */
+ float3 dp1dt = float4_to_float3(catmull_rom_basis_derivative(curve, u + step_size));
+ dp1dt = (max3(fabs(dp1dt)) < eps) ? float4_to_float3(p1 - p0) : dp1dt;
+ const float3 wn1 = normalize(make_float3(dp1dt.y, -dp1dt.x, 0.0f)) * p1.w;
+
+ if (valid) {
+ /* Construct quad coordinates. */
+ const float3 lp0 = float4_to_float3(p0) + wn0;
+ const float3 lp1 = float4_to_float3(p1) + wn1;
+ const float3 up0 = float4_to_float3(p0) - wn0;
+ const float3 up1 = float4_to_float3(p1) - wn1;
+
+ /* Intersect quad. */
+ float vu, vv, vt;
+ bool valid0 = ribbon_intersect_quad(ray_tfar, lp0, lp1, up1, up0, &vu, &vv, &vt);
+
+ if (valid0) {
+ /* ignore self intersections */
+ const float avoidance_factor = 2.0f;
+ if (avoidance_factor != 0.0f) {
+ float r = mix(p0.w, p1.w, vu);
+ valid0 = vt > avoidance_factor * r;
+ }
+
+ if (valid0) {
+ vv = 2.0f * vv - 1.0f;
+
+ /* Record intersection. */
+ ray_tfar = vt;
+ isect->t = vt;
+ isect->u = u + vu * step_size;
+ isect->v = vv;
+ return true;
+ }
+ }
+ }
+
+ /* Store point for next step. */
+ p0 = p1;
+ wn0 = wn1;
+ }
+ return false;
+}
+
+ccl_device_forceinline bool curve_intersect(KernelGlobals kg,
+ ccl_private Intersection *isect,
+ const float3 P,
+ const float3 dir,
+ const float tmax,
+ int object,
+ int prim,
+ float time,
+ int type)
+{
+ const bool is_motion = (type & PRIMITIVE_MOTION);
+
+ KernelCurve kcurve = kernel_tex_fetch(__curves, prim);
+
+ int k0 = kcurve.first_key + PRIMITIVE_UNPACK_SEGMENT(type);
+ int k1 = k0 + 1;
+ int ka = max(k0 - 1, kcurve.first_key);
+ int kb = min(k1 + 1, kcurve.first_key + kcurve.num_keys - 1);
+
+ float4 curve[4];
+ if (!is_motion) {
+ curve[0] = kernel_tex_fetch(__curve_keys, ka);
+ curve[1] = kernel_tex_fetch(__curve_keys, k0);
+ curve[2] = kernel_tex_fetch(__curve_keys, k1);
+ curve[3] = kernel_tex_fetch(__curve_keys, kb);
+ }
+ else {
+ motion_curve_keys(kg, object, prim, time, ka, k0, k1, kb, curve);
+ }
+
+ if (type & PRIMITIVE_CURVE_RIBBON) {
+ /* todo: adaptive number of subdivisions could help performance here. */
+ const int subdivisions = kernel_data.bvh.curve_subdivisions;
+ if (ribbon_intersect(P, dir, tmax, subdivisions, curve, isect)) {
+ isect->prim = prim;
+ isect->object = object;
+ isect->type = type;
+ return true;
+ }
+
+ return false;
+ }
+ else {
+ if (curve_intersect_recursive(P, dir, tmax, curve, isect)) {
+ isect->prim = prim;
+ isect->object = object;
+ isect->type = type;
+ return true;
+ }
+
+ return false;
+ }
+}
+
+ccl_device_inline void curve_shader_setup(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ float3 P,
+ float3 D,
+ float t,
+ const int isect_object,
+ const int isect_prim)
+{
+ 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 * t);
+ D = safe_normalize_len(D, &t);
+ }
+
+ KernelCurve kcurve = kernel_tex_fetch(__curves, isect_prim);
+
+ int k0 = kcurve.first_key + PRIMITIVE_UNPACK_SEGMENT(sd->type);
+ int k1 = k0 + 1;
+ int ka = max(k0 - 1, kcurve.first_key);
+ int kb = min(k1 + 1, kcurve.first_key + kcurve.num_keys - 1);
+
+ float4 P_curve[4];
+
+ if (!(sd->type & PRIMITIVE_MOTION)) {
+ P_curve[0] = kernel_tex_fetch(__curve_keys, ka);
+ P_curve[1] = kernel_tex_fetch(__curve_keys, k0);
+ P_curve[2] = kernel_tex_fetch(__curve_keys, k1);
+ P_curve[3] = kernel_tex_fetch(__curve_keys, kb);
+ }
+ else {
+ motion_curve_keys(kg, sd->object, sd->prim, sd->time, ka, k0, k1, kb, P_curve);
+ }
+
+ P = P + D * t;
+
+ const float4 dPdu4 = catmull_rom_basis_derivative(P_curve, sd->u);
+ const float3 dPdu = float4_to_float3(dPdu4);
+
+ if (sd->type & PRIMITIVE_CURVE_RIBBON) {
+ /* Rounded smooth normals for ribbons, to approximate thick curve shape. */
+ const float3 tangent = normalize(dPdu);
+ const float3 bitangent = normalize(cross(tangent, -D));
+ const float sine = sd->v;
+ const float cosine = safe_sqrtf(1.0f - sine * sine);
+
+ sd->N = normalize(sine * bitangent - cosine * normalize(cross(tangent, bitangent)));
+# if 0
+ /* This approximates the position and geometric normal of a thick curve too,
+ * but gives too many issues with wrong self intersections. */
+ const float dPdu_radius = dPdu4.w;
+ sd->Ng = sd->N;
+ P += sd->N * dPdu_radius;
+# endif
+ }
+ else {
+ /* Thick curves, compute normal using direction from inside the curve.
+ * This could be optimized by recording the normal in the intersection,
+ * however for Optix this would go beyond the size of the payload. */
+ /* NOTE: It is possible that P will be the same as P_inside (precision issues, or very small
+ * radius). In this case use the view direction to approximate the normal. */
+ const float3 P_inside = float4_to_float3(catmull_rom_basis_eval(P_curve, sd->u));
+ const float3 N = (!isequal_float3(P, P_inside)) ? normalize(P - P_inside) : -sd->I;
+
+ sd->N = N;
+ sd->v = 0.0f;
+ }
+
+# ifdef __DPDU__
+ /* dPdu/dPdv */
+ sd->dPdu = dPdu;
+# endif
+
+ /* Convert to world space. */
+ if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
+ object_position_transform_auto(kg, sd, &P);
+ object_normal_transform_auto(kg, sd, &sd->N);
+ object_dir_transform_auto(kg, sd, &sd->dPdu);
+ }
+
+ sd->P = P;
+ sd->Ng = (sd->type & PRIMITIVE_CURVE_RIBBON) ? sd->I : sd->N;
+ sd->dPdv = cross(sd->dPdu, sd->Ng);
+ sd->shader = kernel_tex_fetch(__curves, sd->prim).shader_id;
+}
+
+#endif
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/geom/geom.h b/intern/cycles/kernel/geom/geom.h
index 4de824cc277..efc296c8d39 100644
--- a/intern/cycles/kernel/geom/geom.h
+++ b/intern/cycles/kernel/geom/geom.h
@@ -17,21 +17,24 @@
#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/motion_point.h"
+#include "kernel/geom/point.h"
+#include "kernel/geom/point_intersect.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_attribute.h b/intern/cycles/kernel/geom/geom_attribute.h
deleted file mode 100644
index 9532a21fec7..00000000000
--- a/intern/cycles/kernel/geom/geom_attribute.h
+++ /dev/null
@@ -1,116 +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
-
-/* Attributes
- *
- * We support an arbitrary number of attributes on various mesh elements.
- * On vertices, triangles, curve keys, curves, meshes and volume grids.
- * Most of the code for attribute reading is in the primitive files.
- *
- * Lookup of attributes is different between OSL and SVM, as OSL is ustring
- * based while for SVM we use integer ids. */
-
-ccl_device_inline uint subd_triangle_patch(const KernelGlobals *kg, const ShaderData *sd);
-
-ccl_device_inline uint attribute_primitive_type(const KernelGlobals *kg, const ShaderData *sd)
-{
- if ((sd->type & PRIMITIVE_ALL_TRIANGLE) && subd_triangle_patch(kg, sd) != ~0) {
- return ATTR_PRIM_SUBD;
- }
- else {
- return ATTR_PRIM_GEOMETRY;
- }
-}
-
-ccl_device_inline AttributeDescriptor attribute_not_found()
-{
- const AttributeDescriptor desc = {
- ATTR_ELEMENT_NONE, (NodeAttributeType)0, 0, ATTR_STD_NOT_FOUND};
- return desc;
-}
-
-/* Find attribute based on ID */
-
-ccl_device_inline uint object_attribute_map_offset(const KernelGlobals *kg, int object)
-{
- return kernel_tex_fetch(__objects, object).attribute_map_offset;
-}
-
-ccl_device_inline AttributeDescriptor find_attribute(const KernelGlobals *kg,
- const ShaderData *sd,
- uint id)
-{
- if (sd->object == OBJECT_NONE) {
- return attribute_not_found();
- }
-
- /* for SVM, find attribute by unique id */
- uint attr_offset = object_attribute_map_offset(kg, sd->object);
- attr_offset += attribute_primitive_type(kg, sd);
- uint4 attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
-
- while (attr_map.x != id) {
- if (UNLIKELY(attr_map.x == ATTR_STD_NONE)) {
- if (UNLIKELY(attr_map.y == 0)) {
- return attribute_not_found();
- }
- else {
- /* Chain jump to a different part of the table. */
- attr_offset = attr_map.z;
- }
- }
- else {
- attr_offset += ATTR_PRIM_TYPES;
- }
- attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
- }
-
- AttributeDescriptor desc;
- desc.element = (AttributeElement)attr_map.y;
-
- if (sd->prim == PRIM_NONE && desc.element != ATTR_ELEMENT_MESH &&
- desc.element != ATTR_ELEMENT_VOXEL && desc.element != ATTR_ELEMENT_OBJECT) {
- return attribute_not_found();
- }
-
- /* return result */
- desc.offset = (attr_map.y == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : (int)attr_map.z;
- desc.type = (NodeAttributeType)(attr_map.w & 0xff);
- desc.flags = (AttributeFlag)(attr_map.w >> 8);
-
- return desc;
-}
-
-/* Transform matrix attribute on meshes */
-
-ccl_device Transform primitive_attribute_matrix(const KernelGlobals *kg,
- const ShaderData *sd,
- const AttributeDescriptor desc)
-{
- Transform tfm;
-
- tfm.x = kernel_tex_fetch(__attributes_float3, desc.offset + 0);
- tfm.y = kernel_tex_fetch(__attributes_float3, desc.offset + 1);
- tfm.z = kernel_tex_fetch(__attributes_float3, desc.offset + 2);
-
- return tfm;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/geom/geom_curve.h b/intern/cycles/kernel/geom/geom_curve.h
deleted file mode 100644
index a827a67ce7a..00000000000
--- a/intern/cycles/kernel/geom/geom_curve.h
+++ /dev/null
@@ -1,328 +0,0 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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
-
-/* Curve Primitive
- *
- * Curve primitive for rendering hair and fur. These can be render as flat
- * ribbons or curves with actual thickness. The curve can also be rendered as
- * line segments rather than curves for better performance.
- */
-
-#ifdef __HAIR__
-
-/* Reading attributes on various curve elements */
-
-ccl_device float curve_attribute_float(const KernelGlobals *kg,
- const ShaderData *sd,
- const AttributeDescriptor desc,
- float *dx,
- float *dy)
-{
- if (desc.element & (ATTR_ELEMENT_CURVE_KEY | ATTR_ELEMENT_CURVE_KEY_MOTION)) {
- float4 curvedata = kernel_tex_fetch(__curves, sd->prim);
- int k0 = __float_as_int(curvedata.x) + PRIMITIVE_UNPACK_SEGMENT(sd->type);
- int k1 = k0 + 1;
-
- float f0 = kernel_tex_fetch(__attributes_float, desc.offset + k0);
- float f1 = kernel_tex_fetch(__attributes_float, desc.offset + k1);
-
-# ifdef __RAY_DIFFERENTIALS__
- if (dx)
- *dx = sd->du.dx * (f1 - f0);
- if (dy)
- *dy = 0.0f;
-# endif
-
- return (1.0f - sd->u) * f0 + sd->u * f1;
- }
- else {
-# ifdef __RAY_DIFFERENTIALS__
- if (dx)
- *dx = 0.0f;
- if (dy)
- *dy = 0.0f;
-# endif
-
- if (desc.element & (ATTR_ELEMENT_CURVE | ATTR_ELEMENT_OBJECT | ATTR_ELEMENT_MESH)) {
- const int offset = (desc.element == ATTR_ELEMENT_CURVE) ? desc.offset + sd->prim :
- desc.offset;
- return kernel_tex_fetch(__attributes_float, offset);
- }
- else {
- return 0.0f;
- }
- }
-}
-
-ccl_device float2 curve_attribute_float2(const KernelGlobals *kg,
- const ShaderData *sd,
- const AttributeDescriptor desc,
- float2 *dx,
- float2 *dy)
-{
- if (desc.element & (ATTR_ELEMENT_CURVE_KEY | ATTR_ELEMENT_CURVE_KEY_MOTION)) {
- float4 curvedata = kernel_tex_fetch(__curves, sd->prim);
- int k0 = __float_as_int(curvedata.x) + PRIMITIVE_UNPACK_SEGMENT(sd->type);
- int k1 = k0 + 1;
-
- float2 f0 = kernel_tex_fetch(__attributes_float2, desc.offset + k0);
- float2 f1 = kernel_tex_fetch(__attributes_float2, desc.offset + k1);
-
-# ifdef __RAY_DIFFERENTIALS__
- if (dx)
- *dx = sd->du.dx * (f1 - f0);
- if (dy)
- *dy = make_float2(0.0f, 0.0f);
-# endif
-
- return (1.0f - sd->u) * f0 + sd->u * f1;
- }
- else {
- /* idea: we can't derive any useful differentials here, but for tiled
- * mipmap image caching it would be useful to avoid reading the highest
- * detail level always. maybe a derivative based on the hair density
- * could be computed somehow? */
-# ifdef __RAY_DIFFERENTIALS__
- if (dx)
- *dx = make_float2(0.0f, 0.0f);
- if (dy)
- *dy = make_float2(0.0f, 0.0f);
-# endif
-
- if (desc.element & (ATTR_ELEMENT_CURVE | ATTR_ELEMENT_OBJECT | ATTR_ELEMENT_MESH)) {
- const int offset = (desc.element == ATTR_ELEMENT_CURVE) ? desc.offset + sd->prim :
- desc.offset;
- return kernel_tex_fetch(__attributes_float2, offset);
- }
- else {
- return make_float2(0.0f, 0.0f);
- }
- }
-}
-
-ccl_device float3 curve_attribute_float3(const KernelGlobals *kg,
- const ShaderData *sd,
- const AttributeDescriptor desc,
- float3 *dx,
- float3 *dy)
-{
- if (desc.element & (ATTR_ELEMENT_CURVE_KEY | ATTR_ELEMENT_CURVE_KEY_MOTION)) {
- float4 curvedata = kernel_tex_fetch(__curves, sd->prim);
- int k0 = __float_as_int(curvedata.x) + PRIMITIVE_UNPACK_SEGMENT(sd->type);
- int k1 = k0 + 1;
-
- float3 f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + k0));
- float3 f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + k1));
-
-# ifdef __RAY_DIFFERENTIALS__
- if (dx)
- *dx = sd->du.dx * (f1 - f0);
- if (dy)
- *dy = make_float3(0.0f, 0.0f, 0.0f);
-# endif
-
- return (1.0f - sd->u) * f0 + sd->u * f1;
- }
- else {
-# ifdef __RAY_DIFFERENTIALS__
- if (dx)
- *dx = make_float3(0.0f, 0.0f, 0.0f);
- if (dy)
- *dy = make_float3(0.0f, 0.0f, 0.0f);
-# endif
-
- if (desc.element & (ATTR_ELEMENT_CURVE | ATTR_ELEMENT_OBJECT | ATTR_ELEMENT_MESH)) {
- const int offset = (desc.element == ATTR_ELEMENT_CURVE) ? desc.offset + sd->prim :
- desc.offset;
- return float4_to_float3(kernel_tex_fetch(__attributes_float3, offset));
- }
- else {
- return make_float3(0.0f, 0.0f, 0.0f);
- }
- }
-}
-
-ccl_device float4 curve_attribute_float4(const KernelGlobals *kg,
- const ShaderData *sd,
- const AttributeDescriptor desc,
- float4 *dx,
- float4 *dy)
-{
- if (desc.element & (ATTR_ELEMENT_CURVE_KEY | ATTR_ELEMENT_CURVE_KEY_MOTION)) {
- float4 curvedata = kernel_tex_fetch(__curves, sd->prim);
- int k0 = __float_as_int(curvedata.x) + PRIMITIVE_UNPACK_SEGMENT(sd->type);
- int k1 = k0 + 1;
-
- float4 f0 = kernel_tex_fetch(__attributes_float3, desc.offset + k0);
- float4 f1 = kernel_tex_fetch(__attributes_float3, desc.offset + k1);
-
-# ifdef __RAY_DIFFERENTIALS__
- if (dx)
- *dx = sd->du.dx * (f1 - f0);
- if (dy)
- *dy = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
-# endif
-
- return (1.0f - sd->u) * f0 + sd->u * f1;
- }
- else {
-# ifdef __RAY_DIFFERENTIALS__
- 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);
-# endif
-
- if (desc.element & (ATTR_ELEMENT_CURVE | ATTR_ELEMENT_OBJECT | ATTR_ELEMENT_MESH)) {
- const int offset = (desc.element == ATTR_ELEMENT_CURVE) ? desc.offset + sd->prim :
- desc.offset;
- return kernel_tex_fetch(__attributes_float3, offset);
- }
- else {
- return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
- }
- }
-}
-
-/* Curve thickness */
-
-ccl_device float curve_thickness(const KernelGlobals *kg, const ShaderData *sd)
-{
- float r = 0.0f;
-
- if (sd->type & PRIMITIVE_ALL_CURVE) {
- float4 curvedata = kernel_tex_fetch(__curves, sd->prim);
- int k0 = __float_as_int(curvedata.x) + PRIMITIVE_UNPACK_SEGMENT(sd->type);
- int k1 = k0 + 1;
-
- float4 P_curve[2];
-
- if (!(sd->type & PRIMITIVE_ALL_MOTION)) {
- P_curve[0] = kernel_tex_fetch(__curve_keys, k0);
- P_curve[1] = kernel_tex_fetch(__curve_keys, k1);
- }
- else {
- motion_curve_keys_linear(kg, sd->object, sd->prim, sd->time, k0, k1, P_curve);
- }
-
- r = (P_curve[1].w - P_curve[0].w) * sd->u + P_curve[0].w;
- }
-
- return r * 2.0f;
-}
-
-/* Curve location for motion pass, linear interpolation between keys and
- * ignoring radius because we do the same for the motion keys */
-
-ccl_device float3 curve_motion_center_location(const KernelGlobals *kg, const ShaderData *sd)
-{
- float4 curvedata = kernel_tex_fetch(__curves, sd->prim);
- int k0 = __float_as_int(curvedata.x) + PRIMITIVE_UNPACK_SEGMENT(sd->type);
- int k1 = k0 + 1;
-
- float4 P_curve[2];
-
- P_curve[0] = kernel_tex_fetch(__curve_keys, k0);
- P_curve[1] = kernel_tex_fetch(__curve_keys, k1);
-
- return float4_to_float3(P_curve[1]) * sd->u + float4_to_float3(P_curve[0]) * (1.0f - sd->u);
-}
-
-/* Curve tangent normal */
-
-ccl_device float3 curve_tangent_normal(const KernelGlobals *kg, const ShaderData *sd)
-{
- float3 tgN = make_float3(0.0f, 0.0f, 0.0f);
-
- if (sd->type & PRIMITIVE_ALL_CURVE) {
-
- tgN = -(-sd->I - sd->dPdu * (dot(sd->dPdu, -sd->I) / len_squared(sd->dPdu)));
- tgN = normalize(tgN);
-
- /* need to find suitable scaled gd for corrected normal */
-# if 0
- tgN = normalize(tgN - gd * sd->dPdu);
-# endif
- }
-
- return tgN;
-}
-
-/* Curve bounds utility function */
-
-ccl_device_inline void curvebounds(float *lower,
- float *upper,
- float *extremta,
- float *extrema,
- float *extremtb,
- float *extremb,
- float p0,
- float p1,
- float p2,
- float p3)
-{
- float halfdiscroot = (p2 * p2 - 3 * p3 * p1);
- float ta = -1.0f;
- float tb = -1.0f;
-
- *extremta = -1.0f;
- *extremtb = -1.0f;
- *upper = p0;
- *lower = (p0 + p1) + (p2 + p3);
- *extrema = *upper;
- *extremb = *lower;
-
- if (*lower >= *upper) {
- *upper = *lower;
- *lower = p0;
- }
-
- if (halfdiscroot >= 0) {
- float inv3p3 = (1.0f / 3.0f) / p3;
- halfdiscroot = sqrtf(halfdiscroot);
- ta = (-p2 - halfdiscroot) * inv3p3;
- tb = (-p2 + halfdiscroot) * inv3p3;
- }
-
- float t2;
- float t3;
-
- if (ta > 0.0f && ta < 1.0f) {
- t2 = ta * ta;
- t3 = t2 * ta;
- *extremta = ta;
- *extrema = p3 * t3 + p2 * t2 + p1 * ta + p0;
-
- *upper = fmaxf(*extrema, *upper);
- *lower = fminf(*extrema, *lower);
- }
-
- if (tb > 0.0f && tb < 1.0f) {
- t2 = tb * tb;
- t3 = t2 * tb;
- *extremtb = tb;
- *extremb = p3 * t3 + p2 * t2 + p1 * tb + p0;
-
- *upper = fmaxf(*extremb, *upper);
- *lower = fminf(*extremb, *lower);
- }
-}
-
-#endif /* __HAIR__ */
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/geom/geom_curve_intersect.h b/intern/cycles/kernel/geom/geom_curve_intersect.h
deleted file mode 100644
index b2101034bb6..00000000000
--- a/intern/cycles/kernel/geom/geom_curve_intersect.h
+++ /dev/null
@@ -1,794 +0,0 @@
-/*
- * Copyright 2009-2020 Intel Corporation. Adapted from Embree with
- * with modifications.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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
-
-/* Curve primitive intersection functions.
- *
- * The code here was adapted from curve_intersector_sweep.h in Embree, to get
- * an exact match between Embree CPU ray-tracing and our GPU ray-tracing. */
-
-#define CURVE_NUM_BEZIER_SUBDIVISIONS 3
-#define CURVE_NUM_BEZIER_SUBDIVISIONS_UNSTABLE (CURVE_NUM_BEZIER_SUBDIVISIONS + 1)
-#define CURVE_NUM_BEZIER_STEPS 2
-#define CURVE_NUM_JACOBIAN_ITERATIONS 5
-
-#ifdef __HAIR__
-
-/* Catmull-rom curve evaluation. */
-
-ccl_device_inline float4 catmull_rom_basis_eval(const float4 curve[4], float u)
-{
- const float t = u;
- const float s = 1.0f - u;
- const float n0 = -t * s * s;
- const float n1 = 2.0f + t * t * (3.0f * t - 5.0f);
- const float n2 = 2.0f + s * s * (3.0f * s - 5.0f);
- const float n3 = -s * t * t;
- return 0.5f * (curve[0] * n0 + curve[1] * n1 + curve[2] * n2 + curve[3] * n3);
-}
-
-ccl_device_inline float4 catmull_rom_basis_derivative(const float4 curve[4], float u)
-{
- const float t = u;
- const float s = 1.0f - u;
- const float n0 = -s * s + 2.0f * s * t;
- const float n1 = 2.0f * t * (3.0f * t - 5.0f) + 3.0f * t * t;
- const float n2 = 2.0f * s * (3.0f * t + 2.0f) - 3.0f * s * s;
- const float n3 = -2.0f * s * t + t * t;
- return 0.5f * (curve[0] * n0 + curve[1] * n1 + curve[2] * n2 + curve[3] * n3);
-}
-
-ccl_device_inline float4 catmull_rom_basis_derivative2(const float4 curve[4], float u)
-{
-
- const float t = u;
- const float n0 = -3.0f * t + 2.0f;
- const float n1 = 9.0f * t - 5.0f;
- const float n2 = -9.0f * t + 4.0f;
- const float n3 = 3.0f * t - 1.0f;
- return (curve[0] * n0 + curve[1] * n1 + curve[2] * n2 + curve[3] * n3);
-}
-
-/* Thick Curve */
-
-ccl_device_inline float3 dnormalize(const float3 p, const float3 dp)
-{
- const float pp = dot(p, p);
- const float pdp = dot(p, dp);
- return (pp * dp - pdp * p) / (pp * sqrtf(pp));
-}
-
-ccl_device_inline float sqr_point_to_line_distance(const float3 PmQ0, const float3 Q1mQ0)
-{
- const float3 N = cross(PmQ0, Q1mQ0);
- const float3 D = Q1mQ0;
- return dot(N, N) / dot(D, D);
-}
-
-ccl_device_inline bool cylinder_intersect(const float3 cylinder_start,
- const float3 cylinder_end,
- const float cylinder_radius,
- const float3 ray_dir,
- float2 *t_o,
- float *u0_o,
- float3 *Ng0_o,
- float *u1_o,
- float3 *Ng1_o)
-{
- /* Calculate quadratic equation to solve. */
- const float rl = 1.0f / len(cylinder_end - cylinder_start);
- const float3 P0 = cylinder_start, dP = (cylinder_end - cylinder_start) * rl;
- const float3 O = -P0, dO = ray_dir;
-
- const float dOdO = dot(dO, dO);
- const float OdO = dot(dO, O);
- const float OO = dot(O, O);
- const float dOz = dot(dP, dO);
- const float Oz = dot(dP, O);
-
- const float A = dOdO - sqr(dOz);
- const float B = 2.0f * (OdO - dOz * Oz);
- const float C = OO - sqr(Oz) - sqr(cylinder_radius);
-
- /* We miss the cylinder if determinant is smaller than zero. */
- const float D = B * B - 4.0f * A * C;
- if (!(D >= 0.0f)) {
- *t_o = make_float2(FLT_MAX, -FLT_MAX);
- return false;
- }
-
- /* Special case for rays that are parallel to the cylinder. */
- const float eps = 16.0f * FLT_EPSILON * max(fabsf(dOdO), fabsf(sqr(dOz)));
- if (fabsf(A) < eps) {
- if (C <= 0.0f) {
- *t_o = make_float2(-FLT_MAX, FLT_MAX);
- return true;
- }
- else {
- *t_o = make_float2(-FLT_MAX, FLT_MAX);
- return false;
- }
- }
-
- /* Standard case for rays that are not parallel to the cylinder. */
- const float Q = sqrtf(D);
- const float rcp_2A = 1.0f / (2.0f * A);
- const float t0 = (-B - Q) * rcp_2A;
- const float t1 = (-B + Q) * rcp_2A;
-
- /* Calculates u and Ng for near hit. */
- {
- *u0_o = (t0 * dOz + Oz) * rl;
- const float3 Pr = t0 * ray_dir;
- const float3 Pl = (*u0_o) * (cylinder_end - cylinder_start) + cylinder_start;
- *Ng0_o = Pr - Pl;
- }
-
- /* Calculates u and Ng for far hit. */
- {
- *u1_o = (t1 * dOz + Oz) * rl;
- const float3 Pr = t1 * ray_dir;
- const float3 Pl = (*u1_o) * (cylinder_end - cylinder_start) + cylinder_start;
- *Ng1_o = Pr - Pl;
- }
-
- *t_o = make_float2(t0, t1);
-
- return true;
-}
-
-ccl_device_inline float2 half_plane_intersect(const float3 P, const float3 N, const float3 ray_dir)
-{
- const float3 O = -P;
- const float3 D = ray_dir;
- const float ON = dot(O, N);
- const float DN = dot(D, N);
- const float min_rcp_input = 1e-18f;
- const bool eps = fabsf(DN) < min_rcp_input;
- const float t = -ON / DN;
- const float lower = (eps || DN < 0.0f) ? -FLT_MAX : t;
- const float upper = (eps || DN > 0.0f) ? FLT_MAX : t;
- return make_float2(lower, upper);
-}
-
-ccl_device bool curve_intersect_iterative(const float3 ray_dir,
- float *ray_tfar,
- const float dt,
- const float4 curve[4],
- float u,
- float t,
- const bool use_backfacing,
- Intersection *isect)
-{
- const float length_ray_dir = len(ray_dir);
-
- /* Error of curve evaluations is proportional to largest coordinate. */
- const float4 box_min = min(min(curve[0], curve[1]), min(curve[2], curve[3]));
- const float4 box_max = max(min(curve[0], curve[1]), max(curve[2], curve[3]));
- const float4 box_abs = max(fabs(box_min), fabs(box_max));
- const float P_err = 16.0f * FLT_EPSILON *
- max(box_abs.x, max(box_abs.y, max(box_abs.z, box_abs.w)));
- const float radius_max = box_max.w;
-
- for (int i = 0; i < CURVE_NUM_JACOBIAN_ITERATIONS; i++) {
- const float3 Q = ray_dir * t;
- const float3 dQdt = ray_dir;
- const float Q_err = 16.0f * FLT_EPSILON * length_ray_dir * t;
-
- const float4 P4 = catmull_rom_basis_eval(curve, u);
- const float4 dPdu4 = catmull_rom_basis_derivative(curve, u);
-
- const float3 P = float4_to_float3(P4);
- const float3 dPdu = float4_to_float3(dPdu4);
- const float radius = P4.w;
- const float dradiusdu = dPdu4.w;
-
- const float3 ddPdu = float4_to_float3(catmull_rom_basis_derivative2(curve, u));
-
- const float3 R = Q - P;
- const float len_R = len(R);
- const float R_err = max(Q_err, P_err);
- const float3 dRdu = -dPdu;
- const float3 dRdt = dQdt;
-
- const float3 T = normalize(dPdu);
- const float3 dTdu = dnormalize(dPdu, ddPdu);
- const float cos_err = P_err / len(dPdu);
-
- const float f = dot(R, T);
- const float f_err = len_R * P_err + R_err + cos_err * (1.0f + len_R);
- const float dfdu = dot(dRdu, T) + dot(R, dTdu);
- const float dfdt = dot(dRdt, T);
-
- const float K = dot(R, R) - sqr(f);
- const float dKdu = (dot(R, dRdu) - f * dfdu);
- const float dKdt = (dot(R, dRdt) - f * dfdt);
- const float rsqrt_K = inversesqrtf(K);
-
- const float g = sqrtf(K) - radius;
- const float g_err = R_err + f_err + 16.0f * FLT_EPSILON * radius_max;
- const float dgdu = dKdu * rsqrt_K - dradiusdu;
- const float dgdt = dKdt * rsqrt_K;
-
- const float invdet = 1.0f / (dfdu * dgdt - dgdu * dfdt);
- u -= (dgdt * f - dfdt * g) * invdet;
- t -= (-dgdu * f + dfdu * g) * invdet;
-
- if (fabsf(f) < f_err && fabsf(g) < g_err) {
- t += dt;
- if (!(0.0f <= t && t <= *ray_tfar)) {
- return false; /* Rejects NaNs */
- }
- if (!(u >= 0.0f && u <= 1.0f)) {
- return false; /* Rejects NaNs */
- }
-
- /* Back-face culling. */
- const float3 R = normalize(Q - P);
- const float3 U = dradiusdu * R + dPdu;
- const float3 V = cross(dPdu, R);
- const float3 Ng = cross(V, U);
- if (!use_backfacing && dot(ray_dir, Ng) > 0.0f) {
- return false;
- }
-
- /* Record intersection. */
- *ray_tfar = t;
- isect->t = t;
- isect->u = u;
- isect->v = 0.0f;
-
- return true;
- }
- }
- return false;
-}
-
-ccl_device bool curve_intersect_recursive(const float3 ray_orig,
- const float3 ray_dir,
- float ray_tfar,
- float4 curve[4],
- Intersection *isect)
-{
- /* Move ray closer to make intersection stable. */
- const float3 center = float4_to_float3(0.25f * (curve[0] + curve[1] + curve[2] + curve[3]));
- const float dt = dot(center - ray_orig, ray_dir) / dot(ray_dir, ray_dir);
- const float3 ref = ray_orig + ray_dir * dt;
- const float4 ref4 = make_float4(ref.x, ref.y, ref.z, 0.0f);
- curve[0] -= ref4;
- curve[1] -= ref4;
- curve[2] -= ref4;
- curve[3] -= ref4;
-
- const bool use_backfacing = false;
- const float step_size = 1.0f / (float)(CURVE_NUM_BEZIER_STEPS);
-
- int depth = 0;
-
- /* todo: optimize stack for GPU somehow? Possibly some bitflags are enough, and
- * u0/u1 can be derived from the depth. */
- struct {
- float u0, u1;
- int i;
- } stack[CURVE_NUM_BEZIER_SUBDIVISIONS_UNSTABLE];
-
- bool found = false;
-
- float u0 = 0.0f;
- float u1 = 1.0f;
- int i = 0;
-
- while (1) {
- for (; i < CURVE_NUM_BEZIER_STEPS; i++) {
- const float step = i * step_size;
-
- /* Subdivide curve. */
- const float dscale = (u1 - u0) * (1.0f / 3.0f) * step_size;
- const float vu0 = mix(u0, u1, step);
- const float vu1 = mix(u0, u1, step + step_size);
-
- const float4 P0 = catmull_rom_basis_eval(curve, vu0);
- const float4 dP0du = dscale * catmull_rom_basis_derivative(curve, vu0);
- const float4 P3 = catmull_rom_basis_eval(curve, vu1);
- const float4 dP3du = dscale * catmull_rom_basis_derivative(curve, vu1);
-
- const float4 P1 = P0 + dP0du;
- const float4 P2 = P3 - dP3du;
-
- /* Calculate bounding cylinders. */
- const float rr1 = sqr_point_to_line_distance(float4_to_float3(dP0du),
- float4_to_float3(P3 - P0));
- const float rr2 = sqr_point_to_line_distance(float4_to_float3(dP3du),
- float4_to_float3(P3 - P0));
- const float maxr12 = sqrtf(max(rr1, rr2));
- const float one_plus_ulp = 1.0f + 2.0f * FLT_EPSILON;
- const float one_minus_ulp = 1.0f - 2.0f * FLT_EPSILON;
- float r_outer = max(max(P0.w, P1.w), max(P2.w, P3.w)) + maxr12;
- float r_inner = min(min(P0.w, P1.w), min(P2.w, P3.w)) - maxr12;
- r_outer = one_plus_ulp * r_outer;
- r_inner = max(0.0f, one_minus_ulp * r_inner);
- bool valid = true;
-
- /* Intersect with outer cylinder. */
- float2 tc_outer;
- float u_outer0, u_outer1;
- float3 Ng_outer0, Ng_outer1;
- valid = cylinder_intersect(float4_to_float3(P0),
- float4_to_float3(P3),
- r_outer,
- ray_dir,
- &tc_outer,
- &u_outer0,
- &Ng_outer0,
- &u_outer1,
- &Ng_outer1);
- if (!valid) {
- continue;
- }
-
- /* Intersect with cap-planes. */
- float2 tp = make_float2(-dt, ray_tfar - dt);
- tp = make_float2(max(tp.x, tc_outer.x), min(tp.y, tc_outer.y));
- const float2 h0 = half_plane_intersect(
- float4_to_float3(P0), float4_to_float3(dP0du), ray_dir);
- tp = make_float2(max(tp.x, h0.x), min(tp.y, h0.y));
- const float2 h1 = half_plane_intersect(
- float4_to_float3(P3), -float4_to_float3(dP3du), ray_dir);
- tp = make_float2(max(tp.x, h1.x), min(tp.y, h1.y));
- valid = tp.x <= tp.y;
- if (!valid) {
- continue;
- }
-
- /* Clamp and correct u parameter. */
- u_outer0 = clamp(u_outer0, 0.0f, 1.0f);
- u_outer1 = clamp(u_outer1, 0.0f, 1.0f);
- u_outer0 = mix(u0, u1, (step + u_outer0) * (1.0f / (float)(CURVE_NUM_BEZIER_STEPS + 1)));
- u_outer1 = mix(u0, u1, (step + u_outer1) * (1.0f / (float)(CURVE_NUM_BEZIER_STEPS + 1)));
-
- /* Intersect with inner cylinder. */
- float2 tc_inner;
- float u_inner0, u_inner1;
- float3 Ng_inner0, Ng_inner1;
- const bool valid_inner = cylinder_intersect(float4_to_float3(P0),
- float4_to_float3(P3),
- r_inner,
- ray_dir,
- &tc_inner,
- &u_inner0,
- &Ng_inner0,
- &u_inner1,
- &Ng_inner1);
-
- /* At the unstable area we subdivide deeper. */
-# if 0
- const bool unstable0 = (!valid_inner) |
- (fabsf(dot(normalize(ray_dir), normalize(Ng_inner0))) < 0.3f);
- const bool unstable1 = (!valid_inner) |
- (fabsf(dot(normalize(ray_dir), normalize(Ng_inner1))) < 0.3f);
-# else
- /* On the GPU appears to be a little faster if always enabled. */
- (void)valid_inner;
-
- const bool unstable0 = true;
- const bool unstable1 = true;
-# endif
-
- /* Subtract the inner interval from the current hit interval. */
- float2 tp0 = make_float2(tp.x, min(tp.y, tc_inner.x));
- float2 tp1 = make_float2(max(tp.x, tc_inner.y), tp.y);
- bool valid0 = valid && (tp0.x <= tp0.y);
- bool valid1 = valid && (tp1.x <= tp1.y);
- if (!(valid0 || valid1)) {
- continue;
- }
-
- /* Process one or two hits. */
- bool recurse = false;
- if (valid0) {
- const int termDepth = unstable0 ? CURVE_NUM_BEZIER_SUBDIVISIONS_UNSTABLE :
- CURVE_NUM_BEZIER_SUBDIVISIONS;
- if (depth >= termDepth) {
- found |= curve_intersect_iterative(
- ray_dir, &ray_tfar, dt, curve, u_outer0, tp0.x, use_backfacing, isect);
- }
- else {
- recurse = true;
- }
- }
-
- if (valid1 && (tp1.x + dt <= ray_tfar)) {
- const int termDepth = unstable1 ? CURVE_NUM_BEZIER_SUBDIVISIONS_UNSTABLE :
- CURVE_NUM_BEZIER_SUBDIVISIONS;
- if (depth >= termDepth) {
- found |= curve_intersect_iterative(
- ray_dir, &ray_tfar, dt, curve, u_outer1, tp1.y, use_backfacing, isect);
- }
- else {
- recurse = true;
- }
- }
-
- if (recurse) {
- stack[depth].u0 = u0;
- stack[depth].u1 = u1;
- stack[depth].i = i + 1;
- depth++;
-
- u0 = vu0;
- u1 = vu1;
- i = -1;
- }
- }
-
- if (depth > 0) {
- depth--;
- u0 = stack[depth].u0;
- u1 = stack[depth].u1;
- i = stack[depth].i;
- }
- else {
- break;
- }
- }
-
- return found;
-}
-
-/* Ribbons */
-
-ccl_device_inline bool cylinder_culling_test(const float2 p1, const float2 p2, const float r)
-{
- /* Performs culling against a cylinder. */
- const float2 dp = p2 - p1;
- const float num = dp.x * p1.y - dp.y * p1.x;
- const float den2 = dot(dp, dp);
- return num * num <= r * r * den2;
-}
-
-/**
- * Intersects a ray with a quad with back-face culling
- * enabled. The quad v0,v1,v2,v3 is split into two triangles
- * v0,v1,v3 and v2,v3,v1. The edge v1,v2 decides which of the two
- * triangles gets intersected.
- */
-ccl_device_inline bool ribbon_intersect_quad(const float ray_tfar,
- const float3 quad_v0,
- const float3 quad_v1,
- const float3 quad_v2,
- const float3 quad_v3,
- float *u_o,
- float *v_o,
- float *t_o)
-{
- /* Calculate vertices relative to ray origin? */
- const float3 O = make_float3(0.0f, 0.0f, 0.0f);
- const float3 D = make_float3(0.0f, 0.0f, 1.0f);
- const float3 va = quad_v0 - O;
- const float3 vb = quad_v1 - O;
- const float3 vc = quad_v2 - O;
- const float3 vd = quad_v3 - O;
-
- const float3 edb = vb - vd;
- const float WW = dot(cross(vd, edb), D);
- const float3 v0 = (WW <= 0.0f) ? va : vc;
- const float3 v1 = (WW <= 0.0f) ? vb : vd;
- const float3 v2 = (WW <= 0.0f) ? vd : vb;
-
- /* Calculate edges? */
- const float3 e0 = v2 - v0;
- const float3 e1 = v0 - v1;
-
- /* perform edge tests */
- const float U = dot(cross(v0, e0), D);
- const float V = dot(cross(v1, e1), D);
- if (!(max(U, V) <= 0.0f)) {
- return false;
- }
-
- /* Calculate geometry normal and denominator? */
- const float3 Ng = cross(e1, e0);
- const float den = dot(Ng, D);
- const float rcpDen = 1.0f / den;
-
- /* Perform depth test? */
- const float t = rcpDen * dot(v0, Ng);
- if (!(0.0f <= t && t <= ray_tfar)) {
- return false;
- }
-
- /* Avoid division by 0? */
- if (!(den != 0.0f)) {
- return false;
- }
-
- /* Update hit information? */
- *t_o = t;
- *u_o = U * rcpDen;
- *v_o = V * rcpDen;
- *u_o = (WW <= 0.0f) ? *u_o : 1.0f - *u_o;
- *v_o = (WW <= 0.0f) ? *v_o : 1.0f - *v_o;
- return true;
-}
-
-ccl_device_inline void ribbon_ray_space(const float3 ray_dir, float3 ray_space[3])
-{
- const float3 dx0 = make_float3(0, ray_dir.z, -ray_dir.y);
- const float3 dx1 = make_float3(-ray_dir.z, 0, ray_dir.x);
- ray_space[0] = normalize(dot(dx0, dx0) > dot(dx1, dx1) ? dx0 : dx1);
- ray_space[1] = normalize(cross(ray_dir, ray_space[0]));
- ray_space[2] = ray_dir;
-}
-
-ccl_device_inline float4 ribbon_to_ray_space(const float3 ray_space[3],
- const float3 ray_org,
- const float4 P4)
-{
- float3 P = float4_to_float3(P4) - ray_org;
- return make_float4(dot(ray_space[0], P), dot(ray_space[1], P), dot(ray_space[2], P), P4.w);
-}
-
-ccl_device_inline bool ribbon_intersect(const float3 ray_org,
- const float3 ray_dir,
- float ray_tfar,
- const int N,
- float4 curve[4],
- Intersection *isect)
-{
- /* Transform control points into ray space. */
- float3 ray_space[3];
- ribbon_ray_space(ray_dir, ray_space);
-
- curve[0] = ribbon_to_ray_space(ray_space, ray_org, curve[0]);
- curve[1] = ribbon_to_ray_space(ray_space, ray_org, curve[1]);
- curve[2] = ribbon_to_ray_space(ray_space, ray_org, curve[2]);
- curve[3] = ribbon_to_ray_space(ray_space, ray_org, curve[3]);
-
- const float4 mx = max(max(fabs(curve[0]), fabs(curve[1])), max(fabs(curve[2]), fabs(curve[3])));
- const float eps = 4.0f * FLT_EPSILON * max(max(mx.x, mx.y), max(mx.z, mx.w));
- const float step_size = 1.0f / (float)N;
-
- /* Evaluate first point and radius scaled normal direction. */
- float4 p0 = catmull_rom_basis_eval(curve, 0.0f);
- float3 dp0dt = float4_to_float3(catmull_rom_basis_derivative(curve, 0.0f));
- if (max3(fabs(dp0dt)) < eps) {
- const float4 p1 = catmull_rom_basis_eval(curve, step_size);
- dp0dt = float4_to_float3(p1 - p0);
- }
- float3 wn0 = normalize(make_float3(dp0dt.y, -dp0dt.x, 0.0f)) * p0.w;
-
- /* Evaluate the bezier curve. */
- for (int i = 0; i < N; i++) {
- const float u = i * step_size;
- const float4 p1 = catmull_rom_basis_eval(curve, u + step_size);
- const bool valid = cylinder_culling_test(
- make_float2(p0.x, p0.y), make_float2(p1.x, p1.y), max(p0.w, p1.w));
-
- /* Evaluate next point. */
- float3 dp1dt = float4_to_float3(catmull_rom_basis_derivative(curve, u + step_size));
- dp1dt = (max3(fabs(dp1dt)) < eps) ? float4_to_float3(p1 - p0) : dp1dt;
- const float3 wn1 = normalize(make_float3(dp1dt.y, -dp1dt.x, 0.0f)) * p1.w;
-
- if (valid) {
- /* Construct quad coordinates. */
- const float3 lp0 = float4_to_float3(p0) + wn0;
- const float3 lp1 = float4_to_float3(p1) + wn1;
- const float3 up0 = float4_to_float3(p0) - wn0;
- const float3 up1 = float4_to_float3(p1) - wn1;
-
- /* Intersect quad. */
- float vu, vv, vt;
- bool valid0 = ribbon_intersect_quad(ray_tfar, lp0, lp1, up1, up0, &vu, &vv, &vt);
-
- if (valid0) {
- /* ignore self intersections */
- const float avoidance_factor = 2.0f;
- if (avoidance_factor != 0.0f) {
- float r = mix(p0.w, p1.w, vu);
- valid0 = vt > avoidance_factor * r;
- }
-
- if (valid0) {
- vv = 2.0f * vv - 1.0f;
-
- /* Record intersection. */
- ray_tfar = vt;
- isect->t = vt;
- isect->u = u + vu * step_size;
- isect->v = vv;
- return true;
- }
- }
- }
-
- /* Store point for next step. */
- p0 = p1;
- wn0 = wn1;
- }
- return false;
-}
-
-ccl_device_forceinline bool curve_intersect(const KernelGlobals *kg,
- Intersection *isect,
- const float3 P,
- const float3 dir,
- const float tmax,
- uint visibility,
- int object,
- int curveAddr,
- float time,
- int type)
-{
- const bool is_motion = (type & PRIMITIVE_ALL_MOTION);
-
-# ifndef __KERNEL_OPTIX__ /* See OptiX motion flag OPTIX_MOTION_FLAG_[START|END]_VANISH */
- if (is_motion && kernel_data.bvh.use_bvh_steps) {
- const float2 prim_time = kernel_tex_fetch(__prim_time, curveAddr);
- if (time < prim_time.x || time > prim_time.y) {
- return false;
- }
- }
-# endif
-
- int segment = PRIMITIVE_UNPACK_SEGMENT(type);
- int prim = kernel_tex_fetch(__prim_index, curveAddr);
-
- float4 v00 = kernel_tex_fetch(__curves, prim);
-
- int k0 = __float_as_int(v00.x) + segment;
- int k1 = k0 + 1;
-
- int ka = max(k0 - 1, __float_as_int(v00.x));
- int kb = min(k1 + 1, __float_as_int(v00.x) + __float_as_int(v00.y) - 1);
-
- float4 curve[4];
- if (!is_motion) {
- curve[0] = kernel_tex_fetch(__curve_keys, ka);
- curve[1] = kernel_tex_fetch(__curve_keys, k0);
- curve[2] = kernel_tex_fetch(__curve_keys, k1);
- curve[3] = kernel_tex_fetch(__curve_keys, kb);
- }
- else {
- int fobject = (object == OBJECT_NONE) ? kernel_tex_fetch(__prim_object, curveAddr) : object;
- motion_curve_keys(kg, fobject, prim, time, ka, k0, k1, kb, curve);
- }
-
-# ifdef __VISIBILITY_FLAG__
- if (!(kernel_tex_fetch(__prim_visibility, curveAddr) & visibility)) {
- return false;
- }
-# endif
-
- if (type & (PRIMITIVE_CURVE_RIBBON | PRIMITIVE_MOTION_CURVE_RIBBON)) {
- /* todo: adaptive number of subdivisions could help performance here. */
- const int subdivisions = kernel_data.bvh.curve_subdivisions;
- if (ribbon_intersect(P, dir, tmax, subdivisions, curve, isect)) {
- isect->prim = curveAddr;
- isect->object = object;
- isect->type = type;
- return true;
- }
-
- return false;
- }
- else {
- if (curve_intersect_recursive(P, dir, tmax, curve, isect)) {
- isect->prim = curveAddr;
- isect->object = object;
- isect->type = type;
- return true;
- }
-
- return false;
- }
-}
-
-ccl_device_inline void curve_shader_setup(const KernelGlobals *kg,
- ShaderData *sd,
- float3 P,
- float3 D,
- float t,
- const int isect_object,
- const int isect_prim)
-{
- if (isect_object != OBJECT_NONE) {
- const Transform tfm = object_get_inverse_transform(kg, sd);
-
- P = transform_point(&tfm, P);
- D = transform_direction(&tfm, D * t);
- D = safe_normalize_len(D, &t);
- }
-
- int prim = kernel_tex_fetch(__prim_index, isect_prim);
- float4 v00 = kernel_tex_fetch(__curves, prim);
-
- int k0 = __float_as_int(v00.x) + PRIMITIVE_UNPACK_SEGMENT(sd->type);
- int k1 = k0 + 1;
-
- int ka = max(k0 - 1, __float_as_int(v00.x));
- int kb = min(k1 + 1, __float_as_int(v00.x) + __float_as_int(v00.y) - 1);
-
- float4 P_curve[4];
-
- if (!(sd->type & PRIMITIVE_ALL_MOTION)) {
- P_curve[0] = kernel_tex_fetch(__curve_keys, ka);
- P_curve[1] = kernel_tex_fetch(__curve_keys, k0);
- P_curve[2] = kernel_tex_fetch(__curve_keys, k1);
- P_curve[3] = kernel_tex_fetch(__curve_keys, kb);
- }
- else {
- motion_curve_keys(kg, sd->object, sd->prim, sd->time, ka, k0, k1, kb, P_curve);
- }
-
- P = P + D * t;
-
- const float4 dPdu4 = catmull_rom_basis_derivative(P_curve, sd->u);
- const float3 dPdu = float4_to_float3(dPdu4);
-
- if (sd->type & (PRIMITIVE_CURVE_RIBBON | PRIMITIVE_MOTION_CURVE_RIBBON)) {
- /* Rounded smooth normals for ribbons, to approximate thick curve shape. */
- const float3 tangent = normalize(dPdu);
- const float3 bitangent = normalize(cross(tangent, -D));
- const float sine = sd->v;
- const float cosine = safe_sqrtf(1.0f - sine * sine);
-
- sd->N = normalize(sine * bitangent - cosine * normalize(cross(tangent, bitangent)));
- sd->Ng = -D;
-
-# if 0
- /* This approximates the position and geometric normal of a thick curve too,
- * but gives too many issues with wrong self intersections. */
- const float dPdu_radius = dPdu4.w;
- sd->Ng = sd->N;
- P += sd->N * dPdu_radius;
-# endif
- }
- else {
- /* Thick curves, compute normal using direction from inside the curve.
- * This could be optimized by recording the normal in the intersection,
- * however for Optix this would go beyond the size of the payload. */
- const float3 P_inside = float4_to_float3(catmull_rom_basis_eval(P_curve, sd->u));
- const float3 Ng = normalize(P - P_inside);
-
- sd->N = Ng;
- sd->Ng = Ng;
- sd->v = 0.0f;
- }
-
-# ifdef __DPDU__
- /* dPdu/dPdv */
- sd->dPdu = dPdu;
- sd->dPdv = cross(dPdu, sd->Ng);
-# endif
-
- if (isect_object != OBJECT_NONE) {
- const Transform tfm = object_get_transform(kg, sd);
- P = transform_point(&tfm, P);
- }
-
- sd->P = P;
-
- float4 curvedata = kernel_tex_fetch(__curves, sd->prim);
- sd->shader = __float_as_int(curvedata.z);
-}
-
-#endif
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/geom/geom_motion_curve.h b/intern/cycles/kernel/geom/geom_motion_curve.h
deleted file mode 100644
index 5294da03145..00000000000
--- a/intern/cycles/kernel/geom/geom_motion_curve.h
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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
-
-/* Motion Curve Primitive
- *
- * These are stored as regular curves, plus extra positions and radii at times
- * other than the frame center. Computing the curve keys at a given ray time is
- * a matter of interpolation of the two steps between which the ray time lies.
- *
- * The extra curve keys are stored as ATTR_STD_MOTION_VERTEX_POSITION.
- */
-
-#ifdef __HAIR__
-
-ccl_device_inline int find_attribute_curve_motion(const KernelGlobals *kg,
- int object,
- uint id,
- AttributeElement *elem)
-{
- /* todo: find a better (faster) solution for this, maybe store offset per object.
- *
- * NOTE: currently it's not a bottleneck because in test scenes the loop below runs
- * zero iterations and rendering is really slow with motion curves. For until other
- * areas are speed up it's probably not so crucial to optimize this out.
- */
- uint attr_offset = object_attribute_map_offset(kg, object) + ATTR_PRIM_GEOMETRY;
- uint4 attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
-
- while (attr_map.x != id) {
- attr_offset += ATTR_PRIM_TYPES;
- attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
- }
-
- *elem = (AttributeElement)attr_map.y;
-
- /* return result */
- return (attr_map.y == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : (int)attr_map.z;
-}
-
-ccl_device_inline void motion_curve_keys_for_step_linear(const KernelGlobals *kg,
- int offset,
- int numkeys,
- int numsteps,
- int step,
- int k0,
- int k1,
- float4 keys[2])
-{
- if (step == numsteps) {
- /* center step: regular key location */
- keys[0] = kernel_tex_fetch(__curve_keys, k0);
- keys[1] = kernel_tex_fetch(__curve_keys, k1);
- }
- else {
- /* center step is not stored in this array */
- if (step > numsteps)
- step--;
-
- offset += step * numkeys;
-
- keys[0] = kernel_tex_fetch(__attributes_float3, offset + k0);
- keys[1] = kernel_tex_fetch(__attributes_float3, offset + k1);
- }
-}
-
-/* return 2 curve key locations */
-ccl_device_inline void motion_curve_keys_linear(
- const KernelGlobals *kg, int object, int prim, float time, int k0, int k1, float4 keys[2])
-{
- /* get motion info */
- int numsteps, numkeys;
- object_motion_info(kg, object, &numsteps, NULL, &numkeys);
-
- /* 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 */
- AttributeElement elem;
- int offset = find_attribute_curve_motion(kg, object, ATTR_STD_MOTION_VERTEX_POSITION, &elem);
- kernel_assert(offset != ATTR_STD_NOT_FOUND);
-
- /* fetch key coordinates */
- float4 next_keys[2];
-
- motion_curve_keys_for_step_linear(kg, offset, numkeys, numsteps, step, k0, k1, keys);
- motion_curve_keys_for_step_linear(kg, offset, numkeys, numsteps, step + 1, k0, k1, next_keys);
-
- /* interpolate between steps */
- keys[0] = (1.0f - t) * keys[0] + t * next_keys[0];
- keys[1] = (1.0f - t) * keys[1] + t * next_keys[1];
-}
-
-ccl_device_inline void motion_curve_keys_for_step(const KernelGlobals *kg,
- int offset,
- int numkeys,
- int numsteps,
- int step,
- int k0,
- int k1,
- int k2,
- int k3,
- float4 keys[4])
-{
- if (step == numsteps) {
- /* center step: regular key location */
- keys[0] = kernel_tex_fetch(__curve_keys, k0);
- keys[1] = kernel_tex_fetch(__curve_keys, k1);
- keys[2] = kernel_tex_fetch(__curve_keys, k2);
- keys[3] = kernel_tex_fetch(__curve_keys, k3);
- }
- else {
- /* center step is not stored in this array */
- if (step > numsteps)
- step--;
-
- offset += step * numkeys;
-
- keys[0] = kernel_tex_fetch(__attributes_float3, offset + k0);
- keys[1] = kernel_tex_fetch(__attributes_float3, offset + k1);
- keys[2] = kernel_tex_fetch(__attributes_float3, offset + k2);
- keys[3] = kernel_tex_fetch(__attributes_float3, offset + k3);
- }
-}
-
-/* return 2 curve key locations */
-ccl_device_inline void motion_curve_keys(const KernelGlobals *kg,
- int object,
- int prim,
- float time,
- int k0,
- int k1,
- int k2,
- int k3,
- float4 keys[4])
-{
- /* get motion info */
- int numsteps, numkeys;
- object_motion_info(kg, object, &numsteps, NULL, &numkeys);
-
- /* 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 */
- AttributeElement elem;
- int offset = find_attribute_curve_motion(kg, object, ATTR_STD_MOTION_VERTEX_POSITION, &elem);
- kernel_assert(offset != ATTR_STD_NOT_FOUND);
-
- /* fetch key coordinates */
- float4 next_keys[4];
-
- motion_curve_keys_for_step(kg, offset, numkeys, numsteps, step, k0, k1, k2, k3, keys);
- motion_curve_keys_for_step(kg, offset, numkeys, numsteps, step + 1, k0, k1, k2, k3, next_keys);
-
- /* interpolate between steps */
- keys[0] = (1.0f - t) * keys[0] + t * next_keys[0];
- keys[1] = (1.0f - t) * keys[1] + t * next_keys[1];
- keys[2] = (1.0f - t) * keys[2] + t * next_keys[2];
- keys[3] = (1.0f - t) * keys[3] + t * next_keys[3];
-}
-
-#endif
-
-CCL_NAMESPACE_END
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 239bd0a37b2..00000000000
--- a/intern/cycles/kernel/geom/geom_motion_triangle.h
+++ /dev/null
@@ -1,186 +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
-
-CCL_NAMESPACE_BEGIN
-
-/* Time interpolation of vertex positions and normals */
-
-ccl_device_inline int find_attribute_motion(const KernelGlobals *kg,
- int object,
- uint id,
- AttributeElement *elem)
-{
- /* todo: find a better (faster) solution for this, maybe store offset per object */
- uint attr_offset = object_attribute_map_offset(kg, object);
- uint4 attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
-
- while (attr_map.x != id) {
- if (UNLIKELY(attr_map.x == ATTR_STD_NONE)) {
- if (UNLIKELY(attr_map.y == 0)) {
- return (int)ATTR_STD_NOT_FOUND;
- }
- else {
- /* Chain jump to a different part of the table. */
- attr_offset = attr_map.z;
- }
- }
- else {
- attr_offset += ATTR_PRIM_TYPES;
- }
- attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
- }
-
- *elem = (AttributeElement)attr_map.y;
-
- /* return result */
- return (attr_map.y == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : (int)attr_map.z;
-}
-
-ccl_device_inline void motion_triangle_verts_for_step(const 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(__prim_tri_verts, tri_vindex.w + 0));
- verts[1] = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w + 1));
- verts[2] = float4_to_float3(kernel_tex_fetch(__prim_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(const 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(
- const 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 */
- AttributeElement elem;
- int offset = find_attribute_motion(kg, object, ATTR_STD_MOTION_VERTEX_POSITION, &elem);
- 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(
- const 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 */
- AttributeElement elem;
- int offset = find_attribute_motion(kg, object, ATTR_STD_MOTION_VERTEX_NORMAL, &elem);
- 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/geom_motion_triangle_intersect.h
deleted file mode 100644
index ec7e4b07d76..00000000000
--- a/intern/cycles/kernel/geom/geom_motion_triangle_intersect.h
+++ /dev/null
@@ -1,302 +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.
- */
-
-/* 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
-
-CCL_NAMESPACE_BEGIN
-
-/* 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.
- */
-
-ccl_device_inline float3 motion_triangle_refine(const KernelGlobals *kg,
- ShaderData *sd,
- float3 P,
- float3 D,
- float t,
- const int isect_object,
- const int isect_prim,
- float3 verts[3])
-{
-#ifdef __INTERSECTION_REFINE__
- if (isect_object != OBJECT_NONE) {
- 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;
-
- /* Compute refined intersection distance. */
- const float3 e1 = verts[0] - verts[2];
- const float3 e2 = verts[1] - verts[2];
- const float3 s1 = cross(D, e2);
-
- const float invdivisor = 1.0f / dot(s1, e1);
- const float3 d = P - verts[2];
- const float3 s2 = cross(d, e1);
- float rt = dot(e2, s2) * invdivisor;
-
- /* Compute refined position. */
- P = P + D * rt;
-
- if (isect_object != OBJECT_NONE) {
- 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.
- */
-
-#ifdef __BVH_LOCAL__
-# if defined(__KERNEL_CUDA__) && (defined(i386) || defined(_M_IX86))
-ccl_device_noinline
-# else
-ccl_device_inline
-# endif
- float3
- motion_triangle_refine_local(const KernelGlobals *kg,
- ShaderData *sd,
- float3 P,
- float3 D,
- float t,
- const int isect_object,
- const int isect_prim,
- float3 verts[3])
-{
-# ifdef __KERNEL_OPTIX__
- /* t is always in world space with OptiX. */
- return motion_triangle_refine(kg, sd, P, D, t, isect_object, isect_prim, verts);
-# else
-# ifdef __INTERSECTION_REFINE__
- if (isect_object != OBJECT_NONE) {
- 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;
-
- /* compute refined intersection distance */
- const float3 e1 = verts[0] - verts[2];
- const float3 e2 = verts[1] - verts[2];
- const float3 s1 = cross(D, e2);
-
- const float invdivisor = 1.0f / dot(s1, e1);
- const float3 d = P - verts[2];
- const float3 s2 = cross(d, e1);
- float rt = dot(e2, s2) * invdivisor;
-
- P = P + D * rt;
-
- if (isect_object != OBJECT_NONE) {
- const Transform tfm = object_get_transform(kg, sd);
- P = transform_point(&tfm, P);
- }
-
- return P;
-# else /* __INTERSECTION_REFINE__ */
- return P + D * t;
-# endif /* __INTERSECTION_REFINE__ */
-# endif
-}
-#endif /* __BVH_LOCAL__ */
-
-/* Ray intersection. We simply compute the vertex positions at the given ray
- * time and do a ray intersection with the resulting triangle.
- */
-
-ccl_device_inline bool motion_triangle_intersect(const KernelGlobals *kg,
- Intersection *isect,
- float3 P,
- float3 dir,
- float tmax,
- float time,
- uint visibility,
- int object,
- int prim_addr)
-{
- /* Primitive index for vertex location lookup. */
- int prim = kernel_tex_fetch(__prim_index, prim_addr);
- int fobject = (object == OBJECT_NONE) ? kernel_tex_fetch(__prim_object, prim_addr) : object;
- /* Get vertex locations for intersection. */
- float3 verts[3];
- motion_triangle_vertices(kg, fobject, prim, time, verts);
- /* Ray-triangle intersection, unoptimized. */
- float t, u, v;
- if (ray_triangle_intersect(P,
- dir,
- tmax,
-#if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__)
- (ssef *)verts,
-#else
- verts[0],
- verts[1],
- verts[2],
-#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->t = t;
- isect->u = u;
- isect->v = v;
- isect->prim = prim_addr;
- isect->object = object;
- isect->type = PRIMITIVE_MOTION_TRIANGLE;
- return true;
- }
- }
- return false;
-}
-
-/* Special ray intersection routines for local intersections. 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 motion_triangle_intersect_local(const KernelGlobals *kg,
- LocalIntersection *local_isect,
- float3 P,
- float3 dir,
- float time,
- int object,
- int local_object,
- int prim_addr,
- float tmax,
- 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;
- }
- }
-
- /* Primitive index for vertex location lookup. */
- int prim = kernel_tex_fetch(__prim_index, prim_addr);
- /* Get vertex locations for intersection. */
- float3 verts[3];
- motion_triangle_vertices(kg, local_object, prim, time, verts);
- /* Ray-triangle intersection, unoptimized. */
- float t, u, v;
- if (!ray_triangle_intersect(P,
- dir,
- tmax,
-# if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__)
- (ssef *)verts,
-# else
- verts[0],
- verts[1],
- verts[2],
-# 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. */
- Intersection *isect = &local_isect->hits[hit];
- isect->t = t;
- isect->u = u;
- isect->v = v;
- isect->prim = prim_addr;
- isect->object = object;
- isect->type = PRIMITIVE_MOTION_TRIANGLE;
-
- /* Record geometric normal. */
- local_isect->Ng[hit] = normalize(cross(verts[1] - verts[0], verts[2] - verts[0]));
-
- return false;
-}
-#endif /* __BVH_LOCAL__ */
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/geom/geom_motion_triangle_shader.h b/intern/cycles/kernel/geom/geom_motion_triangle_shader.h
deleted file mode 100644
index 85c4f0ca522..00000000000
--- a/intern/cycles/kernel/geom/geom_motion_triangle_shader.h
+++ /dev/null
@@ -1,119 +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.
- */
-
-/* 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
-
-CCL_NAMESPACE_BEGIN
-
-/* Setup of motion triangle specific parts of ShaderData, moved into this one
- * function to more easily share computation of interpolated positions and
- * normals */
-
-/* return 3 triangle vertex normals */
-ccl_device_noinline void motion_triangle_shader_setup(const KernelGlobals *kg,
- ShaderData *sd,
- const float3 P,
- const float3 D,
- const float ray_t,
- const int isect_object,
- const int isect_prim,
- bool is_local)
-{
- /* Get shader. */
- sd->shader = kernel_tex_fetch(__tri_shader, sd->prim);
- /* Get motion info. */
- /* TODO(sergey): This logic is really similar to motion_triangle_vertices(),
- * can we de-duplicate something here?
- */
- int numsteps, numverts;
- object_motion_info(kg, sd->object, &numsteps, &numverts, NULL);
- /* Figure out which steps we need to fetch and their interpolation factor. */
- int maxstep = numsteps * 2;
- int step = min((int)(sd->time * maxstep), maxstep - 1);
- float t = sd->time * maxstep - step;
- /* Find attribute. */
- AttributeElement elem;
- int offset = find_attribute_motion(kg, sd->object, ATTR_STD_MOTION_VERTEX_POSITION, &elem);
- kernel_assert(offset != ATTR_STD_NOT_FOUND);
- /* Fetch vertex coordinates. */
- float3 verts[3], next_verts[3];
- uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, sd->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];
- /* Compute refined position. */
-#ifdef __BVH_LOCAL__
- if (is_local) {
- sd->P = motion_triangle_refine_local(kg, sd, P, D, ray_t, isect_object, isect_prim, verts);
- }
- else
-#endif /* __BVH_LOCAL__*/
- {
- sd->P = motion_triangle_refine(kg, sd, P, D, ray_t, isect_object, isect_prim, verts);
- }
- /* Compute face normal. */
- float3 Ng;
- if (sd->object_flag & SD_OBJECT_NEGATIVE_SCALE_APPLIED) {
- Ng = normalize(cross(verts[2] - verts[0], verts[1] - verts[0]));
- }
- else {
- Ng = normalize(cross(verts[1] - verts[0], verts[2] - verts[0]));
- }
- sd->Ng = Ng;
- sd->N = Ng;
- /* Compute derivatives of P w.r.t. uv. */
-#ifdef __DPDU__
- sd->dPdu = (verts[0] - verts[2]);
- sd->dPdv = (verts[1] - verts[2]);
-#endif
- /* Compute smooth normal. */
- if (sd->shader & SHADER_SMOOTH_NORMAL) {
- /* Find attribute. */
- AttributeElement elem;
- int offset = find_attribute_motion(kg, sd->object, ATTR_STD_MOTION_VERTEX_NORMAL, &elem);
- kernel_assert(offset != ATTR_STD_NOT_FOUND);
- /* Fetch vertex coordinates. */
- float3 normals[3], next_normals[3];
- 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 u = sd->u;
- float v = sd->v;
- float w = 1.0f - u - v;
- sd->N = (u * normals[0] + v * normals[1] + w * normals[2]);
- }
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/geom/geom_object.h b/intern/cycles/kernel/geom/geom_object.h
deleted file mode 100644
index 7d6ad7b4fe3..00000000000
--- a/intern/cycles/kernel/geom/geom_object.h
+++ /dev/null
@@ -1,594 +0,0 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* Object Primitive
- *
- * All mesh and curve primitives are part of an object. The same mesh and curves
- * may be instanced multiple times by different objects.
- *
- * If the mesh is not instanced multiple times, the object will not be explicitly
- * stored as a primitive in the BVH, rather the bare triangles are curved are
- * directly primitives in the BVH with world space locations applied, and the object
- * ID is looked up afterwards. */
-
-#pragma once
-
-CCL_NAMESPACE_BEGIN
-
-/* Object attributes, for now a fixed size and contents */
-
-enum ObjectTransform {
- OBJECT_TRANSFORM = 0,
- OBJECT_INVERSE_TRANSFORM = 1,
-};
-
-enum ObjectVectorTransform { OBJECT_PASS_MOTION_PRE = 0, OBJECT_PASS_MOTION_POST = 1 };
-
-/* Object to world space transformation */
-
-ccl_device_inline Transform object_fetch_transform(const KernelGlobals *kg,
- int object,
- enum ObjectTransform type)
-{
- if (type == OBJECT_INVERSE_TRANSFORM) {
- return kernel_tex_fetch(__objects, object).itfm;
- }
- else {
- return kernel_tex_fetch(__objects, object).tfm;
- }
-}
-
-/* Lamp to world space transformation */
-
-ccl_device_inline Transform lamp_fetch_transform(const KernelGlobals *kg, int lamp, bool inverse)
-{
- if (inverse) {
- return kernel_tex_fetch(__lights, lamp).itfm;
- }
- else {
- return kernel_tex_fetch(__lights, lamp).tfm;
- }
-}
-
-/* Object to world space transformation for motion vectors */
-
-ccl_device_inline Transform object_fetch_motion_pass_transform(const KernelGlobals *kg,
- int object,
- enum ObjectVectorTransform type)
-{
- int offset = object * OBJECT_MOTION_PASS_SIZE + (int)type;
- return kernel_tex_fetch(__object_motion_pass, offset);
-}
-
-/* Motion blurred object transformations */
-
-#ifdef __OBJECT_MOTION__
-ccl_device_inline Transform object_fetch_transform_motion(const KernelGlobals *kg,
- int object,
- float time)
-{
- const uint motion_offset = kernel_tex_fetch(__objects, object).motion_offset;
- const ccl_global DecomposedTransform *motion = &kernel_tex_fetch(__object_motion, motion_offset);
- const uint num_steps = kernel_tex_fetch(__objects, object).numsteps * 2 + 1;
-
- Transform tfm;
- transform_motion_array_interpolate(&tfm, motion, num_steps, time);
-
- return tfm;
-}
-
-ccl_device_inline Transform object_fetch_transform_motion_test(const KernelGlobals *kg,
- int object,
- float time,
- Transform *itfm)
-{
- int object_flag = kernel_tex_fetch(__object_flag, object);
- if (object_flag & SD_OBJECT_MOTION) {
- /* if we do motion blur */
- Transform tfm = object_fetch_transform_motion(kg, object, time);
-
- if (itfm)
- *itfm = transform_quick_inverse(tfm);
-
- return tfm;
- }
- else {
- Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
- if (itfm)
- *itfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
-
- return tfm;
- }
-}
-#endif
-
-/* Get transform matrix for shading point. */
-
-ccl_device_inline Transform object_get_transform(const KernelGlobals *kg, const ShaderData *sd)
-{
-#ifdef __OBJECT_MOTION__
- return (sd->object_flag & SD_OBJECT_MOTION) ?
- sd->ob_tfm_motion :
- object_fetch_transform(kg, sd->object, OBJECT_TRANSFORM);
-#else
- return object_fetch_transform(kg, sd->object, OBJECT_TRANSFORM);
-#endif
-}
-
-ccl_device_inline Transform object_get_inverse_transform(const KernelGlobals *kg,
- const ShaderData *sd)
-{
-#ifdef __OBJECT_MOTION__
- return (sd->object_flag & SD_OBJECT_MOTION) ?
- sd->ob_itfm_motion :
- object_fetch_transform(kg, sd->object, OBJECT_INVERSE_TRANSFORM);
-#else
- return object_fetch_transform(kg, sd->object, OBJECT_INVERSE_TRANSFORM);
-#endif
-}
-/* Transform position from object to world space */
-
-ccl_device_inline void object_position_transform(const KernelGlobals *kg,
- const ShaderData *sd,
- float3 *P)
-{
-#ifdef __OBJECT_MOTION__
- if (sd->object_flag & SD_OBJECT_MOTION) {
- *P = transform_point_auto(&sd->ob_tfm_motion, *P);
- return;
- }
-#endif
-
- Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_TRANSFORM);
- *P = transform_point(&tfm, *P);
-}
-
-/* Transform position from world to object space */
-
-ccl_device_inline void object_inverse_position_transform(const KernelGlobals *kg,
- const ShaderData *sd,
- float3 *P)
-{
-#ifdef __OBJECT_MOTION__
- if (sd->object_flag & SD_OBJECT_MOTION) {
- *P = transform_point_auto(&sd->ob_itfm_motion, *P);
- return;
- }
-#endif
-
- Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_INVERSE_TRANSFORM);
- *P = transform_point(&tfm, *P);
-}
-
-/* Transform normal from world to object space */
-
-ccl_device_inline void object_inverse_normal_transform(const KernelGlobals *kg,
- const ShaderData *sd,
- float3 *N)
-{
-#ifdef __OBJECT_MOTION__
- if (sd->object_flag & SD_OBJECT_MOTION) {
- if ((sd->object != OBJECT_NONE) || (sd->type == PRIMITIVE_LAMP)) {
- *N = normalize(transform_direction_transposed_auto(&sd->ob_tfm_motion, *N));
- }
- return;
- }
-#endif
-
- if (sd->object != OBJECT_NONE) {
- Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_TRANSFORM);
- *N = normalize(transform_direction_transposed(&tfm, *N));
- }
- else if (sd->type == PRIMITIVE_LAMP) {
- Transform tfm = lamp_fetch_transform(kg, sd->lamp, false);
- *N = normalize(transform_direction_transposed(&tfm, *N));
- }
-}
-
-/* Transform normal from object to world space */
-
-ccl_device_inline void object_normal_transform(const KernelGlobals *kg,
- const ShaderData *sd,
- float3 *N)
-{
-#ifdef __OBJECT_MOTION__
- if (sd->object_flag & SD_OBJECT_MOTION) {
- *N = normalize(transform_direction_transposed_auto(&sd->ob_itfm_motion, *N));
- return;
- }
-#endif
-
- Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_INVERSE_TRANSFORM);
- *N = normalize(transform_direction_transposed(&tfm, *N));
-}
-
-/* Transform direction vector from object to world space */
-
-ccl_device_inline void object_dir_transform(const KernelGlobals *kg,
- const ShaderData *sd,
- float3 *D)
-{
-#ifdef __OBJECT_MOTION__
- if (sd->object_flag & SD_OBJECT_MOTION) {
- *D = transform_direction_auto(&sd->ob_tfm_motion, *D);
- return;
- }
-#endif
-
- Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_TRANSFORM);
- *D = transform_direction(&tfm, *D);
-}
-
-/* Transform direction vector from world to object space */
-
-ccl_device_inline void object_inverse_dir_transform(const KernelGlobals *kg,
- const ShaderData *sd,
- float3 *D)
-{
-#ifdef __OBJECT_MOTION__
- if (sd->object_flag & SD_OBJECT_MOTION) {
- *D = transform_direction_auto(&sd->ob_itfm_motion, *D);
- return;
- }
-#endif
-
- const Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_INVERSE_TRANSFORM);
- *D = transform_direction(&tfm, *D);
-}
-
-/* Object center position */
-
-ccl_device_inline float3 object_location(const KernelGlobals *kg, const ShaderData *sd)
-{
- if (sd->object == OBJECT_NONE)
- return make_float3(0.0f, 0.0f, 0.0f);
-
-#ifdef __OBJECT_MOTION__
- if (sd->object_flag & SD_OBJECT_MOTION) {
- return make_float3(sd->ob_tfm_motion.x.w, sd->ob_tfm_motion.y.w, sd->ob_tfm_motion.z.w);
- }
-#endif
-
- Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_TRANSFORM);
- return make_float3(tfm.x.w, tfm.y.w, tfm.z.w);
-}
-
-/* Color of the object */
-
-ccl_device_inline float3 object_color(const KernelGlobals *kg, int object)
-{
- if (object == OBJECT_NONE)
- return make_float3(0.0f, 0.0f, 0.0f);
-
- const ccl_global KernelObject *kobject = &kernel_tex_fetch(__objects, object);
- return make_float3(kobject->color[0], kobject->color[1], kobject->color[2]);
-}
-
-/* Pass ID number of object */
-
-ccl_device_inline float object_pass_id(const KernelGlobals *kg, int object)
-{
- if (object == OBJECT_NONE)
- return 0.0f;
-
- return kernel_tex_fetch(__objects, object).pass_id;
-}
-
-/* Per lamp random number for shader variation */
-
-ccl_device_inline float lamp_random_number(const KernelGlobals *kg, int lamp)
-{
- if (lamp == LAMP_NONE)
- return 0.0f;
-
- return kernel_tex_fetch(__lights, lamp).random;
-}
-
-/* Per object random number for shader variation */
-
-ccl_device_inline float object_random_number(const KernelGlobals *kg, int object)
-{
- if (object == OBJECT_NONE)
- return 0.0f;
-
- return kernel_tex_fetch(__objects, object).random_number;
-}
-
-/* Particle ID from which this object was generated */
-
-ccl_device_inline int object_particle_id(const KernelGlobals *kg, int object)
-{
- if (object == OBJECT_NONE)
- return 0;
-
- return kernel_tex_fetch(__objects, object).particle_index;
-}
-
-/* Generated texture coordinate on surface from where object was instanced */
-
-ccl_device_inline float3 object_dupli_generated(const KernelGlobals *kg, int object)
-{
- if (object == OBJECT_NONE)
- return make_float3(0.0f, 0.0f, 0.0f);
-
- const ccl_global KernelObject *kobject = &kernel_tex_fetch(__objects, object);
- return make_float3(
- kobject->dupli_generated[0], kobject->dupli_generated[1], kobject->dupli_generated[2]);
-}
-
-/* UV texture coordinate on surface from where object was instanced */
-
-ccl_device_inline float3 object_dupli_uv(const KernelGlobals *kg, int object)
-{
- if (object == OBJECT_NONE)
- return make_float3(0.0f, 0.0f, 0.0f);
-
- const ccl_global KernelObject *kobject = &kernel_tex_fetch(__objects, object);
- return make_float3(kobject->dupli_uv[0], kobject->dupli_uv[1], 0.0f);
-}
-
-/* Information about mesh for motion blurred triangles and curves */
-
-ccl_device_inline void object_motion_info(
- const KernelGlobals *kg, int object, int *numsteps, int *numverts, int *numkeys)
-{
- if (numkeys) {
- *numkeys = kernel_tex_fetch(__objects, object).numkeys;
- }
-
- if (numsteps)
- *numsteps = kernel_tex_fetch(__objects, object).numsteps;
- if (numverts)
- *numverts = kernel_tex_fetch(__objects, object).numverts;
-}
-
-/* Offset to an objects patch map */
-
-ccl_device_inline uint object_patch_map_offset(const KernelGlobals *kg, int object)
-{
- if (object == OBJECT_NONE)
- return 0;
-
- return kernel_tex_fetch(__objects, object).patch_map_offset;
-}
-
-/* Volume step size */
-
-ccl_device_inline float object_volume_density(const KernelGlobals *kg, int object)
-{
- if (object == OBJECT_NONE) {
- return 1.0f;
- }
-
- return kernel_tex_fetch(__objects, object).volume_density;
-}
-
-ccl_device_inline float object_volume_step_size(const KernelGlobals *kg, int object)
-{
- if (object == OBJECT_NONE) {
- return kernel_data.background.volume_step_size;
- }
-
- return kernel_tex_fetch(__object_volume_step, object);
-}
-
-/* Pass ID for shader */
-
-ccl_device int shader_pass_id(const KernelGlobals *kg, const ShaderData *sd)
-{
- return kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).pass_id;
-}
-
-/* Cryptomatte ID */
-
-ccl_device_inline float object_cryptomatte_id(const KernelGlobals *kg, int object)
-{
- if (object == OBJECT_NONE)
- return 0.0f;
-
- return kernel_tex_fetch(__objects, object).cryptomatte_object;
-}
-
-ccl_device_inline float object_cryptomatte_asset_id(const KernelGlobals *kg, int object)
-{
- if (object == OBJECT_NONE)
- return 0;
-
- return kernel_tex_fetch(__objects, object).cryptomatte_asset;
-}
-
-/* Particle data from which object was instanced */
-
-ccl_device_inline uint particle_index(const KernelGlobals *kg, int particle)
-{
- return kernel_tex_fetch(__particles, particle).index;
-}
-
-ccl_device float particle_age(const KernelGlobals *kg, int particle)
-{
- return kernel_tex_fetch(__particles, particle).age;
-}
-
-ccl_device float particle_lifetime(const KernelGlobals *kg, int particle)
-{
- return kernel_tex_fetch(__particles, particle).lifetime;
-}
-
-ccl_device float particle_size(const KernelGlobals *kg, int particle)
-{
- return kernel_tex_fetch(__particles, particle).size;
-}
-
-ccl_device float4 particle_rotation(const KernelGlobals *kg, int particle)
-{
- return kernel_tex_fetch(__particles, particle).rotation;
-}
-
-ccl_device float3 particle_location(const KernelGlobals *kg, int particle)
-{
- return float4_to_float3(kernel_tex_fetch(__particles, particle).location);
-}
-
-ccl_device float3 particle_velocity(const KernelGlobals *kg, int particle)
-{
- return float4_to_float3(kernel_tex_fetch(__particles, particle).velocity);
-}
-
-ccl_device float3 particle_angular_velocity(const KernelGlobals *kg, int particle)
-{
- return float4_to_float3(kernel_tex_fetch(__particles, particle).angular_velocity);
-}
-
-/* Object intersection in BVH */
-
-ccl_device_inline float3 bvh_clamp_direction(float3 dir)
-{
- const float ooeps = 8.271806E-25f;
- return make_float3((fabsf(dir.x) > ooeps) ? dir.x : copysignf(ooeps, dir.x),
- (fabsf(dir.y) > ooeps) ? dir.y : copysignf(ooeps, dir.y),
- (fabsf(dir.z) > ooeps) ? dir.z : copysignf(ooeps, dir.z));
-}
-
-ccl_device_inline float3 bvh_inverse_direction(float3 dir)
-{
- return rcp(dir);
-}
-
-/* Transform ray into object space to enter static object in BVH */
-
-ccl_device_inline float bvh_instance_push(
- const KernelGlobals *kg, int object, const Ray *ray, float3 *P, float3 *dir, float3 *idir)
-{
- Transform tfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
-
- *P = transform_point(&tfm, ray->P);
-
- float len;
- *dir = bvh_clamp_direction(normalize_len(transform_direction(&tfm, ray->D), &len));
- *idir = bvh_inverse_direction(*dir);
-
- return len;
-}
-
-/* Transform ray to exit static object in BVH. */
-
-ccl_device_inline float bvh_instance_pop(const KernelGlobals *kg,
- int object,
- const Ray *ray,
- float3 *P,
- float3 *dir,
- float3 *idir,
- float t)
-{
- if (t != FLT_MAX) {
- Transform tfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
- t /= len(transform_direction(&tfm, ray->D));
- }
-
- *P = ray->P;
- *dir = bvh_clamp_direction(ray->D);
- *idir = bvh_inverse_direction(*dir);
-
- return t;
-}
-
-/* Same as above, but returns scale factor to apply to multiple intersection distances */
-
-ccl_device_inline void bvh_instance_pop_factor(const KernelGlobals *kg,
- int object,
- const Ray *ray,
- float3 *P,
- float3 *dir,
- float3 *idir,
- float *t_fac)
-{
- Transform tfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
- *t_fac = 1.0f / len(transform_direction(&tfm, ray->D));
-
- *P = ray->P;
- *dir = bvh_clamp_direction(ray->D);
- *idir = bvh_inverse_direction(*dir);
-}
-
-#ifdef __OBJECT_MOTION__
-/* Transform ray into object space to enter motion blurred object in BVH */
-
-ccl_device_inline float bvh_instance_motion_push(const KernelGlobals *kg,
- int object,
- const Ray *ray,
- float3 *P,
- float3 *dir,
- float3 *idir,
- Transform *itfm)
-{
- object_fetch_transform_motion_test(kg, object, ray->time, itfm);
-
- *P = transform_point(itfm, ray->P);
-
- float len;
- *dir = bvh_clamp_direction(normalize_len(transform_direction(itfm, ray->D), &len));
- *idir = bvh_inverse_direction(*dir);
-
- return len;
-}
-
-/* Transform ray to exit motion blurred object in BVH. */
-
-ccl_device_inline float bvh_instance_motion_pop(const KernelGlobals *kg,
- int object,
- const Ray *ray,
- float3 *P,
- float3 *dir,
- float3 *idir,
- float t,
- Transform *itfm)
-{
- if (t != FLT_MAX) {
- t /= len(transform_direction(itfm, ray->D));
- }
-
- *P = ray->P;
- *dir = bvh_clamp_direction(ray->D);
- *idir = bvh_inverse_direction(*dir);
-
- return t;
-}
-
-/* Same as above, but returns scale factor to apply to multiple intersection distances */
-
-ccl_device_inline void bvh_instance_motion_pop_factor(const KernelGlobals *kg,
- int object,
- const Ray *ray,
- float3 *P,
- float3 *dir,
- float3 *idir,
- float *t_fac,
- Transform *itfm)
-{
- *t_fac = 1.0f / len(transform_direction(itfm, ray->D));
- *P = ray->P;
- *dir = bvh_clamp_direction(ray->D);
- *idir = bvh_inverse_direction(*dir);
-}
-
-#endif
-
-/* TODO: This can be removed when we know if no devices will require explicit
- * address space qualifiers for this case. */
-
-#define object_position_transform_auto object_position_transform
-#define object_dir_transform_auto object_dir_transform
-#define object_normal_transform_auto object_normal_transform
-
-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 ce0fc15f196..00000000000
--- a/intern/cycles/kernel/geom/geom_patch.h
+++ /dev/null
@@ -1,460 +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, float *u, 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(const 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, float *point, 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, float *s, 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, float *u, 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(const KernelGlobals *kg,
- 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(const KernelGlobals *kg,
- 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(const 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(const KernelGlobals *kg,
- const ShaderData *sd,
- int offset,
- int patch,
- float u,
- float v,
- int channel,
- float *du,
- 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(const KernelGlobals *kg,
- const ShaderData *sd,
- int offset,
- int patch,
- float u,
- float v,
- int channel,
- float2 *du,
- 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(const KernelGlobals *kg,
- const ShaderData *sd,
- int offset,
- int patch,
- float u,
- float v,
- int channel,
- float3 *du,
- 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(const KernelGlobals *kg,
- const ShaderData *sd,
- int offset,
- int patch,
- float u,
- float v,
- int channel,
- float4 *du,
- 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(const KernelGlobals *kg,
- const ShaderData *sd,
- int offset,
- int patch,
- float u,
- float v,
- int channel,
- float4 *du,
- 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 ba31b12e817..00000000000
--- a/intern/cycles/kernel/geom/geom_primitive.h
+++ /dev/null
@@ -1,347 +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(const KernelGlobals *kg,
- const ShaderData *sd,
- const AttributeDescriptor desc,
- float *dx,
- 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(const KernelGlobals *kg,
- const ShaderData *sd,
- const AttributeDescriptor desc,
- float2 *dx,
- 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(const KernelGlobals *kg,
- const ShaderData *sd,
- const AttributeDescriptor desc,
- float3 *dx,
- 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(const KernelGlobals *kg,
- const ShaderData *sd,
- const AttributeDescriptor desc,
- float4 *dx,
- 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(const ShaderData *sd,
- const AttributeDescriptor desc)
-{
- return sd->type == PRIMITIVE_VOLUME;
-}
-
-ccl_device_inline float primitive_volume_attribute_float(const KernelGlobals *kg,
- 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(const KernelGlobals *kg,
- 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(const KernelGlobals *kg,
- 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(const KernelGlobals *kg, 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(const KernelGlobals *kg, ShaderData *sd, float2 *uv, 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(const KernelGlobals *kg, 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(const KernelGlobals *kg, 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/geom_shader_data.h
deleted file mode 100644
index fb2cb5cb1ea..00000000000
--- a/intern/cycles/kernel/geom/geom_shader_data.h
+++ /dev/null
@@ -1,373 +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 initialize ShaderData given.
- *
- * Could be from an incoming ray, intersection or sampled position. */
-
-#pragma once
-
-CCL_NAMESPACE_BEGIN
-
-/* ShaderData setup from incoming ray */
-
-#ifdef __OBJECT_MOTION__
-ccl_device void shader_setup_object_transforms(const KernelGlobals *ccl_restrict kg,
- ShaderData *ccl_restrict sd,
- float time)
-{
- if (sd->object_flag & SD_OBJECT_MOTION) {
- sd->ob_tfm_motion = object_fetch_transform_motion(kg, sd->object, time);
- sd->ob_itfm_motion = transform_quick_inverse(sd->ob_tfm_motion);
- }
-}
-#endif
-
-/* TODO: break this up if it helps reduce register pressure to load data from
- * global memory as we write it to shaderdata. */
-ccl_device_inline void shader_setup_from_ray(const KernelGlobals *ccl_restrict kg,
- ShaderData *ccl_restrict sd,
- const Ray *ccl_restrict ray,
- const Intersection *ccl_restrict isect)
-{
- /* Read intersection data into shader globals.
- *
- * TODO: this is redundant, could potentially remove some of this from
- * ShaderData but would need to ensure that it also works for shadow
- * shader evaluation. */
- sd->u = isect->u;
- sd->v = isect->v;
- sd->ray_length = isect->t;
- sd->type = isect->type;
- sd->object = (isect->object == OBJECT_NONE) ? kernel_tex_fetch(__prim_object, isect->prim) :
- isect->object;
- sd->object_flag = kernel_tex_fetch(__object_flag, sd->object);
- sd->prim = kernel_tex_fetch(__prim_index, isect->prim);
- sd->lamp = LAMP_NONE;
- sd->flag = 0;
-
- /* Read matrices and time. */
- sd->time = ray->time;
-
-#ifdef __OBJECT_MOTION__
- shader_setup_object_transforms(kg, sd, ray->time);
-#endif
-
- /* Read ray data into shader globals. */
- sd->I = -ray->D;
-
-#ifdef __HAIR__
- if (sd->type & PRIMITIVE_ALL_CURVE) {
- /* curve */
- curve_shader_setup(kg, sd, ray->P, ray->D, isect->t, isect->object, isect->prim);
- }
- else
-#endif
- if (sd->type & PRIMITIVE_TRIANGLE) {
- /* static triangle */
- float3 Ng = triangle_normal(kg, sd);
- sd->shader = kernel_tex_fetch(__tri_shader, sd->prim);
-
- /* vectors */
- sd->P = triangle_refine(kg, sd, ray->P, ray->D, isect->t, isect->object, isect->prim);
- sd->Ng = Ng;
- sd->N = Ng;
-
- /* smooth normal */
- if (sd->shader & SHADER_SMOOTH_NORMAL)
- sd->N = triangle_smooth_normal(kg, Ng, sd->prim, sd->u, sd->v);
-
-#ifdef __DPDU__
- /* dPdu/dPdv */
- triangle_dPdudv(kg, sd->prim, &sd->dPdu, &sd->dPdv);
-#endif
- }
- else {
- /* motion triangle */
- motion_triangle_shader_setup(
- kg, sd, ray->P, ray->D, isect->t, isect->object, isect->prim, false);
- }
-
- sd->flag |= kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).flags;
-
- if (isect->object != OBJECT_NONE) {
- /* instance transform */
- object_normal_transform_auto(kg, sd, &sd->N);
- object_normal_transform_auto(kg, sd, &sd->Ng);
-#ifdef __DPDU__
- object_dir_transform_auto(kg, sd, &sd->dPdu);
- object_dir_transform_auto(kg, sd, &sd->dPdv);
-#endif
- }
-
- /* backfacing test */
- bool backfacing = (dot(sd->Ng, sd->I) < 0.0f);
-
- if (backfacing) {
- sd->flag |= SD_BACKFACING;
- sd->Ng = -sd->Ng;
- sd->N = -sd->N;
-#ifdef __DPDU__
- sd->dPdu = -sd->dPdu;
- sd->dPdv = -sd->dPdv;
-#endif
- }
-
-#ifdef __RAY_DIFFERENTIALS__
- /* differentials */
- differential_transfer_compact(&sd->dP, ray->dP, ray->D, ray->dD, sd->Ng, sd->ray_length);
- differential_incoming_compact(&sd->dI, ray->D, ray->dD);
- differential_dudv(&sd->du, &sd->dv, sd->dPdu, sd->dPdv, sd->dP, sd->Ng);
-#endif
-}
-
-/* ShaderData setup from position sampled on mesh */
-
-ccl_device_inline void shader_setup_from_sample(const KernelGlobals *ccl_restrict kg,
- ShaderData *ccl_restrict sd,
- const float3 P,
- const float3 Ng,
- const float3 I,
- int shader,
- int object,
- int prim,
- float u,
- float v,
- float t,
- float time,
- bool object_space,
- int lamp)
-{
- /* vectors */
- sd->P = P;
- sd->N = Ng;
- sd->Ng = Ng;
- sd->I = I;
- sd->shader = shader;
- if (prim != PRIM_NONE)
- sd->type = PRIMITIVE_TRIANGLE;
- else if (lamp != LAMP_NONE)
- sd->type = PRIMITIVE_LAMP;
- else
- sd->type = PRIMITIVE_NONE;
-
- /* primitive */
- sd->object = object;
- sd->lamp = LAMP_NONE;
- /* Currently no access to bvh prim index for strand sd->prim. */
- sd->prim = prim;
- sd->u = u;
- sd->v = v;
- sd->time = time;
- sd->ray_length = t;
-
- sd->flag = kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).flags;
- sd->object_flag = 0;
- if (sd->object != OBJECT_NONE) {
- sd->object_flag |= kernel_tex_fetch(__object_flag, sd->object);
-
-#ifdef __OBJECT_MOTION__
- shader_setup_object_transforms(kg, sd, time);
-#endif
- }
- else if (lamp != LAMP_NONE) {
- sd->lamp = lamp;
- }
-
- /* transform into world space */
- if (object_space) {
- object_position_transform_auto(kg, sd, &sd->P);
- object_normal_transform_auto(kg, sd, &sd->Ng);
- sd->N = sd->Ng;
- object_dir_transform_auto(kg, sd, &sd->I);
- }
-
- if (sd->type & PRIMITIVE_TRIANGLE) {
- /* smooth normal */
- if (sd->shader & SHADER_SMOOTH_NORMAL) {
- sd->N = triangle_smooth_normal(kg, Ng, sd->prim, sd->u, sd->v);
-
- if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
- object_normal_transform_auto(kg, sd, &sd->N);
- }
- }
-
- /* dPdu/dPdv */
-#ifdef __DPDU__
- triangle_dPdudv(kg, sd->prim, &sd->dPdu, &sd->dPdv);
-
- if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
- object_dir_transform_auto(kg, sd, &sd->dPdu);
- object_dir_transform_auto(kg, sd, &sd->dPdv);
- }
-#endif
- }
- else {
-#ifdef __DPDU__
- sd->dPdu = zero_float3();
- sd->dPdv = zero_float3();
-#endif
- }
-
- /* backfacing test */
- if (sd->prim != PRIM_NONE) {
- bool backfacing = (dot(sd->Ng, sd->I) < 0.0f);
-
- if (backfacing) {
- sd->flag |= SD_BACKFACING;
- sd->Ng = -sd->Ng;
- sd->N = -sd->N;
-#ifdef __DPDU__
- sd->dPdu = -sd->dPdu;
- sd->dPdv = -sd->dPdv;
-#endif
- }
- }
-
-#ifdef __RAY_DIFFERENTIALS__
- /* no ray differentials here yet */
- sd->dP = differential3_zero();
- sd->dI = differential3_zero();
- sd->du = differential_zero();
- sd->dv = differential_zero();
-#endif
-}
-
-/* ShaderData setup for displacement */
-
-ccl_device void shader_setup_from_displace(const KernelGlobals *ccl_restrict kg,
- ShaderData *ccl_restrict sd,
- int object,
- int prim,
- float u,
- float v)
-{
- float3 P, Ng, I = zero_float3();
- int shader;
-
- triangle_point_normal(kg, object, prim, u, v, &P, &Ng, &shader);
-
- /* force smooth shading for displacement */
- shader |= SHADER_SMOOTH_NORMAL;
-
- shader_setup_from_sample(
- kg,
- sd,
- P,
- Ng,
- I,
- shader,
- object,
- prim,
- u,
- v,
- 0.0f,
- 0.5f,
- !(kernel_tex_fetch(__object_flag, object) & SD_OBJECT_TRANSFORM_APPLIED),
- LAMP_NONE);
-}
-
-/* ShaderData setup from ray into background */
-
-ccl_device_inline void shader_setup_from_background(const KernelGlobals *ccl_restrict kg,
- ShaderData *ccl_restrict sd,
- const float3 ray_P,
- const float3 ray_D,
- const float ray_time)
-{
- /* for NDC coordinates */
- sd->ray_P = ray_P;
-
- /* vectors */
- sd->P = ray_D;
- sd->N = -ray_D;
- sd->Ng = -ray_D;
- sd->I = -ray_D;
- sd->shader = kernel_data.background.surface_shader;
- sd->flag = kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).flags;
- sd->object_flag = 0;
- sd->time = ray_time;
- sd->ray_length = 0.0f;
-
- sd->object = OBJECT_NONE;
- sd->lamp = LAMP_NONE;
- sd->prim = PRIM_NONE;
- sd->u = 0.0f;
- sd->v = 0.0f;
-
-#ifdef __DPDU__
- /* dPdu/dPdv */
- sd->dPdu = zero_float3();
- sd->dPdv = zero_float3();
-#endif
-
-#ifdef __RAY_DIFFERENTIALS__
- /* differentials */
- sd->dP = differential3_zero(); /* TODO: ray->dP */
- differential_incoming(&sd->dI, sd->dP);
- sd->du = differential_zero();
- sd->dv = differential_zero();
-#endif
-}
-
-/* ShaderData setup from point inside volume */
-
-#ifdef __VOLUME__
-ccl_device_inline void shader_setup_from_volume(const KernelGlobals *ccl_restrict kg,
- ShaderData *ccl_restrict sd,
- const Ray *ccl_restrict ray)
-{
-
- /* vectors */
- sd->P = ray->P;
- sd->N = -ray->D;
- sd->Ng = -ray->D;
- sd->I = -ray->D;
- sd->shader = SHADER_NONE;
- sd->flag = 0;
- sd->object_flag = 0;
- sd->time = ray->time;
- sd->ray_length = 0.0f; /* todo: can we set this to some useful value? */
-
- sd->object = OBJECT_NONE; /* todo: fill this for texture coordinates */
- sd->lamp = LAMP_NONE;
- sd->prim = PRIM_NONE;
- sd->type = PRIMITIVE_VOLUME;
-
- sd->u = 0.0f;
- sd->v = 0.0f;
-
-# ifdef __DPDU__
- /* dPdu/dPdv */
- sd->dPdu = zero_float3();
- sd->dPdv = zero_float3();
-# endif
-
-# ifdef __RAY_DIFFERENTIALS__
- /* differentials */
- sd->dP = differential3_zero(); /* TODO ray->dD */
- differential_incoming(&sd->dI, sd->dP);
- sd->du = differential_zero();
- sd->dv = differential_zero();
-# endif
-
- /* for NDC coordinates */
- sd->ray_P = ray->P;
- sd->ray_dP = ray->dP;
-}
-#endif /* __VOLUME__ */
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/geom/geom_subd_triangle.h b/intern/cycles/kernel/geom/geom_subd_triangle.h
deleted file mode 100644
index 877b2ece15b..00000000000
--- a/intern/cycles/kernel/geom/geom_subd_triangle.h
+++ /dev/null
@@ -1,689 +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.
- */
-
-/* Functions for retrieving attributes on triangles produced from subdivision meshes */
-
-#pragma once
-
-CCL_NAMESPACE_BEGIN
-
-/* Patch index for triangle, -1 if not subdivision triangle */
-
-ccl_device_inline uint subd_triangle_patch(const KernelGlobals *kg, const ShaderData *sd)
-{
- return (sd->prim != PRIM_NONE) ? kernel_tex_fetch(__tri_patch, sd->prim) : ~0;
-}
-
-/* UV coords of triangle within patch */
-
-ccl_device_inline void subd_triangle_patch_uv(const KernelGlobals *kg,
- const ShaderData *sd,
- float2 uv[3])
-{
- uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, sd->prim);
-
- uv[0] = kernel_tex_fetch(__tri_patch_uv, tri_vindex.x);
- uv[1] = kernel_tex_fetch(__tri_patch_uv, tri_vindex.y);
- uv[2] = kernel_tex_fetch(__tri_patch_uv, tri_vindex.z);
-}
-
-/* Vertex indices of patch */
-
-ccl_device_inline uint4 subd_triangle_patch_indices(const KernelGlobals *kg, int patch)
-{
- uint4 indices;
-
- indices.x = kernel_tex_fetch(__patches, patch + 0);
- indices.y = kernel_tex_fetch(__patches, patch + 1);
- indices.z = kernel_tex_fetch(__patches, patch + 2);
- indices.w = kernel_tex_fetch(__patches, patch + 3);
-
- return indices;
-}
-
-/* Originating face for patch */
-
-ccl_device_inline uint subd_triangle_patch_face(const KernelGlobals *kg, int patch)
-{
- return kernel_tex_fetch(__patches, patch + 4);
-}
-
-/* Number of corners on originating face */
-
-ccl_device_inline uint subd_triangle_patch_num_corners(const KernelGlobals *kg, int patch)
-{
- return kernel_tex_fetch(__patches, patch + 5) & 0xffff;
-}
-
-/* Indices of the four corners that are used by the patch */
-
-ccl_device_inline void subd_triangle_patch_corners(const KernelGlobals *kg,
- int patch,
- int corners[4])
-{
- uint4 data;
-
- data.x = kernel_tex_fetch(__patches, patch + 4);
- data.y = kernel_tex_fetch(__patches, patch + 5);
- data.z = kernel_tex_fetch(__patches, patch + 6);
- data.w = kernel_tex_fetch(__patches, patch + 7);
-
- int num_corners = data.y & 0xffff;
-
- if (num_corners == 4) {
- /* quad */
- corners[0] = data.z;
- corners[1] = data.z + 1;
- corners[2] = data.z + 2;
- corners[3] = data.z + 3;
- }
- else {
- /* ngon */
- int c = data.y >> 16;
-
- corners[0] = data.z + c;
- corners[1] = data.z + mod(c + 1, num_corners);
- corners[2] = data.w;
- corners[3] = data.z + mod(c - 1, num_corners);
- }
-}
-
-/* Reading attributes on various subdivision triangle elements */
-
-ccl_device_noinline float subd_triangle_attribute_float(const KernelGlobals *kg,
- const ShaderData *sd,
- const AttributeDescriptor desc,
- float *dx,
- float *dy)
-{
- int patch = subd_triangle_patch(kg, sd);
-
-#ifdef __PATCH_EVAL__
- if (desc.flags & ATTR_SUBDIVIDED) {
- float2 uv[3];
- subd_triangle_patch_uv(kg, sd, uv);
-
- float2 dpdu = uv[0] - uv[2];
- float2 dpdv = uv[1] - uv[2];
-
- /* p is [s, t] */
- float2 p = dpdu * sd->u + dpdv * sd->v + uv[2];
-
- float a, dads, dadt;
- a = patch_eval_float(kg, sd, desc.offset, patch, p.x, p.y, 0, &dads, &dadt);
-
-# ifdef __RAY_DIFFERENTIALS__
- if (dx || dy) {
- float dsdu = dpdu.x;
- float dtdu = dpdu.y;
- float dsdv = dpdv.x;
- float dtdv = dpdv.y;
-
- if (dx) {
- float dudx = sd->du.dx;
- float dvdx = sd->dv.dx;
-
- float dsdx = dsdu * dudx + dsdv * dvdx;
- float dtdx = dtdu * dudx + dtdv * dvdx;
-
- *dx = dads * dsdx + dadt * dtdx;
- }
- if (dy) {
- float dudy = sd->du.dy;
- float dvdy = sd->dv.dy;
-
- float dsdy = dsdu * dudy + dsdv * dvdy;
- float dtdy = dtdu * dudy + dtdv * dvdy;
-
- *dy = dads * dsdy + dadt * dtdy;
- }
- }
-# endif
-
- return a;
- }
- else
-#endif /* __PATCH_EVAL__ */
- if (desc.element == ATTR_ELEMENT_FACE) {
- if (dx)
- *dx = 0.0f;
- if (dy)
- *dy = 0.0f;
-
- return kernel_tex_fetch(__attributes_float, desc.offset + subd_triangle_patch_face(kg, patch));
- }
- else if (desc.element == ATTR_ELEMENT_VERTEX || desc.element == ATTR_ELEMENT_VERTEX_MOTION) {
- float2 uv[3];
- subd_triangle_patch_uv(kg, sd, uv);
-
- uint4 v = subd_triangle_patch_indices(kg, patch);
-
- float f0 = kernel_tex_fetch(__attributes_float, desc.offset + v.x);
- float f1 = kernel_tex_fetch(__attributes_float, desc.offset + v.y);
- float f2 = kernel_tex_fetch(__attributes_float, desc.offset + v.z);
- float f3 = kernel_tex_fetch(__attributes_float, desc.offset + v.w);
-
- if (subd_triangle_patch_num_corners(kg, patch) != 4) {
- f1 = (f1 + f0) * 0.5f;
- f3 = (f3 + f0) * 0.5f;
- }
-
- float a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y);
- float b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y);
- float c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y);
-
-#ifdef __RAY_DIFFERENTIALS__
- if (dx)
- *dx = sd->du.dx * a + sd->dv.dx * b - (sd->du.dx + sd->dv.dx) * c;
- if (dy)
- *dy = sd->du.dy * a + sd->dv.dy * b - (sd->du.dy + sd->dv.dy) * c;
-#endif
-
- return sd->u * a + sd->v * b + (1.0f - sd->u - sd->v) * c;
- }
- else if (desc.element == ATTR_ELEMENT_CORNER) {
- float2 uv[3];
- subd_triangle_patch_uv(kg, sd, uv);
-
- int corners[4];
- subd_triangle_patch_corners(kg, patch, corners);
-
- float f0 = kernel_tex_fetch(__attributes_float, corners[0] + desc.offset);
- float f1 = kernel_tex_fetch(__attributes_float, corners[1] + desc.offset);
- float f2 = kernel_tex_fetch(__attributes_float, corners[2] + desc.offset);
- float f3 = kernel_tex_fetch(__attributes_float, corners[3] + desc.offset);
-
- if (subd_triangle_patch_num_corners(kg, patch) != 4) {
- f1 = (f1 + f0) * 0.5f;
- f3 = (f3 + f0) * 0.5f;
- }
-
- float a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y);
- float b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y);
- float c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y);
-
-#ifdef __RAY_DIFFERENTIALS__
- if (dx)
- *dx = sd->du.dx * a + sd->dv.dx * b - (sd->du.dx + sd->dv.dx) * c;
- if (dy)
- *dy = sd->du.dy * a + sd->dv.dy * b - (sd->du.dy + sd->dv.dy) * c;
-#endif
-
- return sd->u * a + sd->v * b + (1.0f - sd->u - sd->v) * c;
- }
- else if (desc.element == ATTR_ELEMENT_OBJECT || desc.element == ATTR_ELEMENT_MESH) {
- if (dx)
- *dx = 0.0f;
- if (dy)
- *dy = 0.0f;
-
- return kernel_tex_fetch(__attributes_float, desc.offset);
- }
- else {
- if (dx)
- *dx = 0.0f;
- if (dy)
- *dy = 0.0f;
-
- return 0.0f;
- }
-}
-
-ccl_device_noinline float2 subd_triangle_attribute_float2(const KernelGlobals *kg,
- const ShaderData *sd,
- const AttributeDescriptor desc,
- float2 *dx,
- float2 *dy)
-{
- int patch = subd_triangle_patch(kg, sd);
-
-#ifdef __PATCH_EVAL__
- if (desc.flags & ATTR_SUBDIVIDED) {
- float2 uv[3];
- subd_triangle_patch_uv(kg, sd, uv);
-
- float2 dpdu = uv[0] - uv[2];
- float2 dpdv = uv[1] - uv[2];
-
- /* p is [s, t] */
- float2 p = dpdu * sd->u + dpdv * sd->v + uv[2];
-
- float2 a, dads, dadt;
-
- a = patch_eval_float2(kg, sd, desc.offset, patch, p.x, p.y, 0, &dads, &dadt);
-
-# ifdef __RAY_DIFFERENTIALS__
- if (dx || dy) {
- float dsdu = dpdu.x;
- float dtdu = dpdu.y;
- float dsdv = dpdv.x;
- float dtdv = dpdv.y;
-
- if (dx) {
- float dudx = sd->du.dx;
- float dvdx = sd->dv.dx;
-
- float dsdx = dsdu * dudx + dsdv * dvdx;
- float dtdx = dtdu * dudx + dtdv * dvdx;
-
- *dx = dads * dsdx + dadt * dtdx;
- }
- if (dy) {
- float dudy = sd->du.dy;
- float dvdy = sd->dv.dy;
-
- float dsdy = dsdu * dudy + dsdv * dvdy;
- float dtdy = dtdu * dudy + dtdv * dvdy;
-
- *dy = dads * dsdy + dadt * dtdy;
- }
- }
-# endif
-
- return a;
- }
- else
-#endif /* __PATCH_EVAL__ */
- if (desc.element == ATTR_ELEMENT_FACE) {
- if (dx)
- *dx = make_float2(0.0f, 0.0f);
- if (dy)
- *dy = make_float2(0.0f, 0.0f);
-
- return kernel_tex_fetch(__attributes_float2,
- desc.offset + subd_triangle_patch_face(kg, patch));
- }
- else if (desc.element == ATTR_ELEMENT_VERTEX || desc.element == ATTR_ELEMENT_VERTEX_MOTION) {
- float2 uv[3];
- subd_triangle_patch_uv(kg, sd, uv);
-
- uint4 v = subd_triangle_patch_indices(kg, patch);
-
- float2 f0 = kernel_tex_fetch(__attributes_float2, desc.offset + v.x);
- float2 f1 = kernel_tex_fetch(__attributes_float2, desc.offset + v.y);
- float2 f2 = kernel_tex_fetch(__attributes_float2, desc.offset + v.z);
- float2 f3 = kernel_tex_fetch(__attributes_float2, desc.offset + v.w);
-
- if (subd_triangle_patch_num_corners(kg, patch) != 4) {
- f1 = (f1 + f0) * 0.5f;
- f3 = (f3 + f0) * 0.5f;
- }
-
- float2 a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y);
- float2 b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y);
- float2 c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y);
-
-#ifdef __RAY_DIFFERENTIALS__
- if (dx)
- *dx = sd->du.dx * a + sd->dv.dx * b - (sd->du.dx + sd->dv.dx) * c;
- if (dy)
- *dy = sd->du.dy * a + sd->dv.dy * b - (sd->du.dy + sd->dv.dy) * c;
-#endif
-
- return sd->u * a + sd->v * b + (1.0f - sd->u - sd->v) * c;
- }
- else if (desc.element == ATTR_ELEMENT_CORNER) {
- float2 uv[3];
- subd_triangle_patch_uv(kg, sd, uv);
-
- int corners[4];
- subd_triangle_patch_corners(kg, patch, corners);
-
- float2 f0, f1, f2, f3;
-
- f0 = kernel_tex_fetch(__attributes_float2, corners[0] + desc.offset);
- f1 = kernel_tex_fetch(__attributes_float2, corners[1] + desc.offset);
- f2 = kernel_tex_fetch(__attributes_float2, corners[2] + desc.offset);
- f3 = kernel_tex_fetch(__attributes_float2, corners[3] + desc.offset);
-
- if (subd_triangle_patch_num_corners(kg, patch) != 4) {
- f1 = (f1 + f0) * 0.5f;
- f3 = (f3 + f0) * 0.5f;
- }
-
- float2 a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y);
- float2 b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y);
- float2 c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y);
-
-#ifdef __RAY_DIFFERENTIALS__
- if (dx)
- *dx = sd->du.dx * a + sd->dv.dx * b - (sd->du.dx + sd->dv.dx) * c;
- if (dy)
- *dy = sd->du.dy * a + sd->dv.dy * b - (sd->du.dy + sd->dv.dy) * c;
-#endif
-
- return sd->u * a + sd->v * b + (1.0f - sd->u - sd->v) * c;
- }
- else if (desc.element == ATTR_ELEMENT_OBJECT || desc.element == ATTR_ELEMENT_MESH) {
- if (dx)
- *dx = make_float2(0.0f, 0.0f);
- if (dy)
- *dy = make_float2(0.0f, 0.0f);
-
- return kernel_tex_fetch(__attributes_float2, desc.offset);
- }
- 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_noinline float3 subd_triangle_attribute_float3(const KernelGlobals *kg,
- const ShaderData *sd,
- const AttributeDescriptor desc,
- float3 *dx,
- float3 *dy)
-{
- int patch = subd_triangle_patch(kg, sd);
-
-#ifdef __PATCH_EVAL__
- if (desc.flags & ATTR_SUBDIVIDED) {
- float2 uv[3];
- subd_triangle_patch_uv(kg, sd, uv);
-
- float2 dpdu = uv[0] - uv[2];
- float2 dpdv = uv[1] - uv[2];
-
- /* p is [s, t] */
- float2 p = dpdu * sd->u + dpdv * sd->v + uv[2];
-
- float3 a, dads, dadt;
- a = patch_eval_float3(kg, sd, desc.offset, patch, p.x, p.y, 0, &dads, &dadt);
-
-# ifdef __RAY_DIFFERENTIALS__
- if (dx || dy) {
- float dsdu = dpdu.x;
- float dtdu = dpdu.y;
- float dsdv = dpdv.x;
- float dtdv = dpdv.y;
-
- if (dx) {
- float dudx = sd->du.dx;
- float dvdx = sd->dv.dx;
-
- float dsdx = dsdu * dudx + dsdv * dvdx;
- float dtdx = dtdu * dudx + dtdv * dvdx;
-
- *dx = dads * dsdx + dadt * dtdx;
- }
- if (dy) {
- float dudy = sd->du.dy;
- float dvdy = sd->dv.dy;
-
- float dsdy = dsdu * dudy + dsdv * dvdy;
- float dtdy = dtdu * dudy + dtdv * dvdy;
-
- *dy = dads * dsdy + dadt * dtdy;
- }
- }
-# endif
-
- return a;
- }
- else
-#endif /* __PATCH_EVAL__ */
- if (desc.element == ATTR_ELEMENT_FACE) {
- if (dx)
- *dx = make_float3(0.0f, 0.0f, 0.0f);
- if (dy)
- *dy = make_float3(0.0f, 0.0f, 0.0f);
-
- return float4_to_float3(
- kernel_tex_fetch(__attributes_float3, desc.offset + subd_triangle_patch_face(kg, patch)));
- }
- else if (desc.element == ATTR_ELEMENT_VERTEX || desc.element == ATTR_ELEMENT_VERTEX_MOTION) {
- float2 uv[3];
- subd_triangle_patch_uv(kg, sd, uv);
-
- uint4 v = subd_triangle_patch_indices(kg, patch);
-
- float3 f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + v.x));
- float3 f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + v.y));
- float3 f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + v.z));
- float3 f3 = float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + v.w));
-
- if (subd_triangle_patch_num_corners(kg, patch) != 4) {
- f1 = (f1 + f0) * 0.5f;
- f3 = (f3 + f0) * 0.5f;
- }
-
- float3 a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y);
- float3 b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y);
- float3 c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y);
-
-#ifdef __RAY_DIFFERENTIALS__
- if (dx)
- *dx = sd->du.dx * a + sd->dv.dx * b - (sd->du.dx + sd->dv.dx) * c;
- if (dy)
- *dy = sd->du.dy * a + sd->dv.dy * b - (sd->du.dy + sd->dv.dy) * c;
-#endif
-
- return sd->u * a + sd->v * b + (1.0f - sd->u - sd->v) * c;
- }
- else if (desc.element == ATTR_ELEMENT_CORNER) {
- float2 uv[3];
- subd_triangle_patch_uv(kg, sd, uv);
-
- int corners[4];
- subd_triangle_patch_corners(kg, patch, corners);
-
- float3 f0, f1, f2, f3;
-
- f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[0] + desc.offset));
- f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[1] + desc.offset));
- f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[2] + desc.offset));
- f3 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[3] + desc.offset));
-
- if (subd_triangle_patch_num_corners(kg, patch) != 4) {
- f1 = (f1 + f0) * 0.5f;
- f3 = (f3 + f0) * 0.5f;
- }
-
- float3 a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y);
- float3 b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y);
- float3 c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y);
-
-#ifdef __RAY_DIFFERENTIALS__
- if (dx)
- *dx = sd->du.dx * a + sd->dv.dx * b - (sd->du.dx + sd->dv.dx) * c;
- if (dy)
- *dy = sd->du.dy * a + sd->dv.dy * b - (sd->du.dy + sd->dv.dy) * c;
-#endif
-
- return sd->u * a + sd->v * b + (1.0f - sd->u - sd->v) * c;
- }
- else if (desc.element == ATTR_ELEMENT_OBJECT || desc.element == ATTR_ELEMENT_MESH) {
- if (dx)
- *dx = make_float3(0.0f, 0.0f, 0.0f);
- if (dy)
- *dy = make_float3(0.0f, 0.0f, 0.0f);
-
- return float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset));
- }
- 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_noinline float4 subd_triangle_attribute_float4(const KernelGlobals *kg,
- const ShaderData *sd,
- const AttributeDescriptor desc,
- float4 *dx,
- float4 *dy)
-{
- int patch = subd_triangle_patch(kg, sd);
-
-#ifdef __PATCH_EVAL__
- if (desc.flags & ATTR_SUBDIVIDED) {
- float2 uv[3];
- subd_triangle_patch_uv(kg, sd, uv);
-
- float2 dpdu = uv[0] - uv[2];
- float2 dpdv = uv[1] - uv[2];
-
- /* p is [s, t] */
- float2 p = dpdu * sd->u + dpdv * sd->v + uv[2];
-
- float4 a, dads, dadt;
- if (desc.type == NODE_ATTR_RGBA) {
- a = patch_eval_uchar4(kg, sd, desc.offset, patch, p.x, p.y, 0, &dads, &dadt);
- }
- else {
- a = patch_eval_float4(kg, sd, desc.offset, patch, p.x, p.y, 0, &dads, &dadt);
- }
-
-# ifdef __RAY_DIFFERENTIALS__
- if (dx || dy) {
- float dsdu = dpdu.x;
- float dtdu = dpdu.y;
- float dsdv = dpdv.x;
- float dtdv = dpdv.y;
-
- if (dx) {
- float dudx = sd->du.dx;
- float dvdx = sd->dv.dx;
-
- float dsdx = dsdu * dudx + dsdv * dvdx;
- float dtdx = dtdu * dudx + dtdv * dvdx;
-
- *dx = dads * dsdx + dadt * dtdx;
- }
- if (dy) {
- float dudy = sd->du.dy;
- float dvdy = sd->dv.dy;
-
- float dsdy = dsdu * dudy + dsdv * dvdy;
- float dtdy = dtdu * dudy + dtdv * dvdy;
-
- *dy = dads * dsdy + dadt * dtdy;
- }
- }
-# endif
-
- return a;
- }
- else
-#endif /* __PATCH_EVAL__ */
- if (desc.element == ATTR_ELEMENT_FACE) {
- 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 kernel_tex_fetch(__attributes_float3,
- desc.offset + subd_triangle_patch_face(kg, patch));
- }
- else if (desc.element == ATTR_ELEMENT_VERTEX || desc.element == ATTR_ELEMENT_VERTEX_MOTION) {
- float2 uv[3];
- subd_triangle_patch_uv(kg, sd, uv);
-
- uint4 v = subd_triangle_patch_indices(kg, patch);
-
- float4 f0 = kernel_tex_fetch(__attributes_float3, desc.offset + v.x);
- float4 f1 = kernel_tex_fetch(__attributes_float3, desc.offset + v.y);
- float4 f2 = kernel_tex_fetch(__attributes_float3, desc.offset + v.z);
- float4 f3 = kernel_tex_fetch(__attributes_float3, desc.offset + v.w);
-
- if (subd_triangle_patch_num_corners(kg, patch) != 4) {
- f1 = (f1 + f0) * 0.5f;
- f3 = (f3 + f0) * 0.5f;
- }
-
- float4 a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y);
- float4 b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y);
- float4 c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y);
-
-#ifdef __RAY_DIFFERENTIALS__
- if (dx)
- *dx = sd->du.dx * a + sd->dv.dx * b - (sd->du.dx + sd->dv.dx) * c;
- if (dy)
- *dy = sd->du.dy * a + sd->dv.dy * b - (sd->du.dy + sd->dv.dy) * c;
-#endif
-
- return sd->u * a + sd->v * b + (1.0f - sd->u - sd->v) * c;
- }
- else if (desc.element == ATTR_ELEMENT_CORNER || desc.element == ATTR_ELEMENT_CORNER_BYTE) {
- float2 uv[3];
- subd_triangle_patch_uv(kg, sd, uv);
-
- int corners[4];
- subd_triangle_patch_corners(kg, patch, corners);
-
- float4 f0, f1, f2, f3;
-
- if (desc.element == ATTR_ELEMENT_CORNER_BYTE) {
- f0 = color_srgb_to_linear_v4(
- color_uchar4_to_float4(kernel_tex_fetch(__attributes_uchar4, corners[0] + desc.offset)));
- f1 = color_srgb_to_linear_v4(
- color_uchar4_to_float4(kernel_tex_fetch(__attributes_uchar4, corners[1] + desc.offset)));
- f2 = color_srgb_to_linear_v4(
- color_uchar4_to_float4(kernel_tex_fetch(__attributes_uchar4, corners[2] + desc.offset)));
- f3 = color_srgb_to_linear_v4(
- color_uchar4_to_float4(kernel_tex_fetch(__attributes_uchar4, corners[3] + desc.offset)));
- }
- else {
- f0 = kernel_tex_fetch(__attributes_float3, corners[0] + desc.offset);
- f1 = kernel_tex_fetch(__attributes_float3, corners[1] + desc.offset);
- f2 = kernel_tex_fetch(__attributes_float3, corners[2] + desc.offset);
- f3 = kernel_tex_fetch(__attributes_float3, corners[3] + desc.offset);
- }
-
- if (subd_triangle_patch_num_corners(kg, patch) != 4) {
- f1 = (f1 + f0) * 0.5f;
- f3 = (f3 + f0) * 0.5f;
- }
-
- float4 a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y);
- float4 b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y);
- float4 c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y);
-
-#ifdef __RAY_DIFFERENTIALS__
- if (dx)
- *dx = sd->du.dx * a + sd->dv.dx * b - (sd->du.dx + sd->dv.dx) * c;
- if (dy)
- *dy = sd->du.dy * a + sd->dv.dy * b - (sd->du.dy + sd->dv.dy) * c;
-#endif
-
- return sd->u * a + sd->v * b + (1.0f - sd->u - sd->v) * c;
- }
- else if (desc.element == ATTR_ELEMENT_OBJECT || desc.element == ATTR_ELEMENT_MESH) {
- 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 kernel_tex_fetch(__attributes_float3, desc.offset);
- }
- 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);
- }
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/geom/geom_triangle.h b/intern/cycles/kernel/geom/geom_triangle.h
deleted file mode 100644
index 910fb122c6d..00000000000
--- a/intern/cycles/kernel/geom/geom_triangle.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.
- */
-
-/* Triangle Primitive
- *
- * Basic triangle with 3 vertices is used to represent mesh surfaces. For BVH
- * ray intersection we use a precomputed triangle storage to accelerate
- * intersection at the cost of more memory usage */
-
-#pragma once
-
-CCL_NAMESPACE_BEGIN
-
-/* Normal on triangle. */
-ccl_device_inline float3 triangle_normal(const KernelGlobals *kg, ShaderData *sd)
-{
- /* load triangle vertices */
- const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, sd->prim);
- const float3 v0 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w + 0));
- const float3 v1 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w + 1));
- const float3 v2 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w + 2));
-
- /* return normal */
- if (sd->object_flag & SD_OBJECT_NEGATIVE_SCALE_APPLIED) {
- return normalize(cross(v2 - v0, v1 - v0));
- }
- else {
- return normalize(cross(v1 - v0, v2 - v0));
- }
-}
-
-/* Point and normal on triangle. */
-ccl_device_inline void triangle_point_normal(const KernelGlobals *kg,
- int object,
- int prim,
- float u,
- float v,
- float3 *P,
- float3 *Ng,
- int *shader)
-{
- /* load triangle vertices */
- const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
- float3 v0 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w + 0));
- float3 v1 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w + 1));
- float3 v2 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w + 2));
- /* compute point */
- float t = 1.0f - u - v;
- *P = (u * v0 + v * v1 + t * v2);
- /* get object flags */
- int object_flag = kernel_tex_fetch(__object_flag, object);
- /* compute normal */
- if (object_flag & SD_OBJECT_NEGATIVE_SCALE_APPLIED) {
- *Ng = normalize(cross(v2 - v0, v1 - v0));
- }
- else {
- *Ng = normalize(cross(v1 - v0, v2 - v0));
- }
- /* shader`*/
- *shader = kernel_tex_fetch(__tri_shader, prim);
-}
-
-/* Triangle vertex locations */
-
-ccl_device_inline void triangle_vertices(const KernelGlobals *kg, int prim, float3 P[3])
-{
- const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
- P[0] = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w + 0));
- P[1] = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w + 1));
- P[2] = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w + 2));
-}
-
-/* Triangle vertex locations and vertex normals */
-
-ccl_device_inline void triangle_vertices_and_normals(const KernelGlobals *kg,
- int prim,
- float3 P[3],
- float3 N[3])
-{
- const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
- P[0] = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w + 0));
- P[1] = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w + 1));
- P[2] = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w + 2));
- N[0] = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.x));
- N[1] = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.y));
- N[2] = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.z));
-}
-
-/* Interpolate smooth vertex normal from vertices */
-
-ccl_device_inline float3
-triangle_smooth_normal(const KernelGlobals *kg, float3 Ng, int prim, float u, float v)
-{
- /* load triangle vertices */
- const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
- float3 n0 = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.x));
- float3 n1 = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.y));
- float3 n2 = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.z));
-
- float3 N = safe_normalize((1.0f - u - v) * n2 + u * n0 + v * n1);
-
- return is_zero(N) ? Ng : N;
-}
-
-ccl_device_inline float3 triangle_smooth_normal_unnormalized(
- const KernelGlobals *kg, const ShaderData *sd, float3 Ng, int prim, float u, float v)
-{
- /* load triangle vertices */
- const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
- float3 n0 = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.x));
- float3 n1 = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.y));
- float3 n2 = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.z));
-
- /* ensure that the normals are in object space */
- if (sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED) {
- object_inverse_normal_transform(kg, sd, &n0);
- object_inverse_normal_transform(kg, sd, &n1);
- object_inverse_normal_transform(kg, sd, &n2);
- }
-
- float3 N = (1.0f - u - v) * n2 + u * n0 + v * n1;
-
- return is_zero(N) ? Ng : N;
-}
-
-/* Ray differentials on triangle */
-
-ccl_device_inline void triangle_dPdudv(const KernelGlobals *kg,
- int prim,
- ccl_addr_space float3 *dPdu,
- ccl_addr_space float3 *dPdv)
-{
- /* fetch triangle vertex coordinates */
- const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
- const float3 p0 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w + 0));
- const float3 p1 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w + 1));
- const float3 p2 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w + 2));
-
- /* compute derivatives of P w.r.t. uv */
- *dPdu = (p0 - p2);
- *dPdv = (p1 - p2);
-}
-
-/* Reading attributes on various triangle elements */
-
-ccl_device float triangle_attribute_float(const KernelGlobals *kg,
- const ShaderData *sd,
- const AttributeDescriptor desc,
- float *dx,
- float *dy)
-{
- if (desc.element & (ATTR_ELEMENT_VERTEX | ATTR_ELEMENT_VERTEX_MOTION | ATTR_ELEMENT_CORNER)) {
- float f0, f1, f2;
-
- if (desc.element & (ATTR_ELEMENT_VERTEX | ATTR_ELEMENT_VERTEX_MOTION)) {
- const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, sd->prim);
- f0 = kernel_tex_fetch(__attributes_float, desc.offset + tri_vindex.x);
- f1 = kernel_tex_fetch(__attributes_float, desc.offset + tri_vindex.y);
- f2 = kernel_tex_fetch(__attributes_float, desc.offset + tri_vindex.z);
- }
- else {
- const int tri = desc.offset + sd->prim * 3;
- f0 = kernel_tex_fetch(__attributes_float, tri + 0);
- f1 = kernel_tex_fetch(__attributes_float, tri + 1);
- f2 = kernel_tex_fetch(__attributes_float, tri + 2);
- }
-
-#ifdef __RAY_DIFFERENTIALS__
- if (dx)
- *dx = sd->du.dx * f0 + sd->dv.dx * f1 - (sd->du.dx + sd->dv.dx) * f2;
- if (dy)
- *dy = sd->du.dy * f0 + sd->dv.dy * f1 - (sd->du.dy + sd->dv.dy) * f2;
-#endif
-
- return sd->u * f0 + sd->v * f1 + (1.0f - sd->u - sd->v) * f2;
- }
- else {
-#ifdef __RAY_DIFFERENTIALS__
- if (dx)
- *dx = 0.0f;
- if (dy)
- *dy = 0.0f;
-#endif
-
- if (desc.element & (ATTR_ELEMENT_FACE | ATTR_ELEMENT_OBJECT | ATTR_ELEMENT_MESH)) {
- const int offset = (desc.element == ATTR_ELEMENT_FACE) ? desc.offset + sd->prim :
- desc.offset;
- return kernel_tex_fetch(__attributes_float, offset);
- }
- else {
- return 0.0f;
- }
- }
-}
-
-ccl_device float2 triangle_attribute_float2(const KernelGlobals *kg,
- const ShaderData *sd,
- const AttributeDescriptor desc,
- float2 *dx,
- float2 *dy)
-{
- if (desc.element & (ATTR_ELEMENT_VERTEX | ATTR_ELEMENT_VERTEX_MOTION | ATTR_ELEMENT_CORNER)) {
- float2 f0, f1, f2;
-
- if (desc.element & (ATTR_ELEMENT_VERTEX | ATTR_ELEMENT_VERTEX_MOTION)) {
- const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, sd->prim);
- f0 = kernel_tex_fetch(__attributes_float2, desc.offset + tri_vindex.x);
- f1 = kernel_tex_fetch(__attributes_float2, desc.offset + tri_vindex.y);
- f2 = kernel_tex_fetch(__attributes_float2, desc.offset + tri_vindex.z);
- }
- else {
- const int tri = desc.offset + sd->prim * 3;
- f0 = kernel_tex_fetch(__attributes_float2, tri + 0);
- f1 = kernel_tex_fetch(__attributes_float2, tri + 1);
- f2 = kernel_tex_fetch(__attributes_float2, tri + 2);
- }
-
-#ifdef __RAY_DIFFERENTIALS__
- if (dx)
- *dx = sd->du.dx * f0 + sd->dv.dx * f1 - (sd->du.dx + sd->dv.dx) * f2;
- if (dy)
- *dy = sd->du.dy * f0 + sd->dv.dy * f1 - (sd->du.dy + sd->dv.dy) * f2;
-#endif
-
- return sd->u * f0 + sd->v * f1 + (1.0f - sd->u - sd->v) * f2;
- }
- else {
-#ifdef __RAY_DIFFERENTIALS__
- if (dx)
- *dx = make_float2(0.0f, 0.0f);
- if (dy)
- *dy = make_float2(0.0f, 0.0f);
-#endif
-
- if (desc.element & (ATTR_ELEMENT_FACE | ATTR_ELEMENT_OBJECT | ATTR_ELEMENT_MESH)) {
- const int offset = (desc.element == ATTR_ELEMENT_FACE) ? desc.offset + sd->prim :
- desc.offset;
- return kernel_tex_fetch(__attributes_float2, offset);
- }
- else {
- return make_float2(0.0f, 0.0f);
- }
- }
-}
-
-ccl_device float3 triangle_attribute_float3(const KernelGlobals *kg,
- const ShaderData *sd,
- const AttributeDescriptor desc,
- float3 *dx,
- float3 *dy)
-{
- if (desc.element & (ATTR_ELEMENT_VERTEX | ATTR_ELEMENT_VERTEX_MOTION | ATTR_ELEMENT_CORNER)) {
- float3 f0, f1, f2;
-
- if (desc.element & (ATTR_ELEMENT_VERTEX | ATTR_ELEMENT_VERTEX_MOTION)) {
- const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, sd->prim);
- f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + tri_vindex.x));
- f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + tri_vindex.y));
- f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + tri_vindex.z));
- }
- else {
- const int tri = desc.offset + sd->prim * 3;
- f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, tri + 0));
- f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, tri + 1));
- f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, tri + 2));
- }
-
-#ifdef __RAY_DIFFERENTIALS__
- if (dx)
- *dx = sd->du.dx * f0 + sd->dv.dx * f1 - (sd->du.dx + sd->dv.dx) * f2;
- if (dy)
- *dy = sd->du.dy * f0 + sd->dv.dy * f1 - (sd->du.dy + sd->dv.dy) * f2;
-#endif
-
- return sd->u * f0 + sd->v * f1 + (1.0f - sd->u - sd->v) * f2;
- }
- else {
-#ifdef __RAY_DIFFERENTIALS__
- if (dx)
- *dx = make_float3(0.0f, 0.0f, 0.0f);
- if (dy)
- *dy = make_float3(0.0f, 0.0f, 0.0f);
-#endif
-
- if (desc.element & (ATTR_ELEMENT_FACE | ATTR_ELEMENT_OBJECT | ATTR_ELEMENT_MESH)) {
- const int offset = (desc.element == ATTR_ELEMENT_FACE) ? desc.offset + sd->prim :
- desc.offset;
- return float4_to_float3(kernel_tex_fetch(__attributes_float3, offset));
- }
- else {
- return make_float3(0.0f, 0.0f, 0.0f);
- }
- }
-}
-
-ccl_device float4 triangle_attribute_float4(const KernelGlobals *kg,
- const ShaderData *sd,
- const AttributeDescriptor desc,
- float4 *dx,
- float4 *dy)
-{
- if (desc.element & (ATTR_ELEMENT_VERTEX | ATTR_ELEMENT_VERTEX_MOTION | ATTR_ELEMENT_CORNER |
- ATTR_ELEMENT_CORNER_BYTE)) {
- float4 f0, f1, f2;
-
- if (desc.element & (ATTR_ELEMENT_VERTEX | ATTR_ELEMENT_VERTEX_MOTION)) {
- const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, sd->prim);
- f0 = kernel_tex_fetch(__attributes_float3, desc.offset + tri_vindex.x);
- f1 = kernel_tex_fetch(__attributes_float3, desc.offset + tri_vindex.y);
- f2 = kernel_tex_fetch(__attributes_float3, desc.offset + tri_vindex.z);
- }
- else {
- const int tri = desc.offset + sd->prim * 3;
- if (desc.element == ATTR_ELEMENT_CORNER) {
- f0 = kernel_tex_fetch(__attributes_float3, tri + 0);
- f1 = kernel_tex_fetch(__attributes_float3, tri + 1);
- f2 = kernel_tex_fetch(__attributes_float3, tri + 2);
- }
- else {
- f0 = color_srgb_to_linear_v4(
- color_uchar4_to_float4(kernel_tex_fetch(__attributes_uchar4, tri + 0)));
- f1 = color_srgb_to_linear_v4(
- color_uchar4_to_float4(kernel_tex_fetch(__attributes_uchar4, tri + 1)));
- f2 = color_srgb_to_linear_v4(
- color_uchar4_to_float4(kernel_tex_fetch(__attributes_uchar4, tri + 2)));
- }
- }
-
-#ifdef __RAY_DIFFERENTIALS__
- if (dx)
- *dx = sd->du.dx * f0 + sd->dv.dx * f1 - (sd->du.dx + sd->dv.dx) * f2;
- if (dy)
- *dy = sd->du.dy * f0 + sd->dv.dy * f1 - (sd->du.dy + sd->dv.dy) * f2;
-#endif
-
- return sd->u * f0 + sd->v * f1 + (1.0f - sd->u - sd->v) * f2;
- }
- else {
-#ifdef __RAY_DIFFERENTIALS__
- 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);
-#endif
-
- if (desc.element & (ATTR_ELEMENT_FACE | ATTR_ELEMENT_OBJECT | ATTR_ELEMENT_MESH)) {
- const int offset = (desc.element == ATTR_ELEMENT_FACE) ? desc.offset + sd->prim :
- desc.offset;
- return kernel_tex_fetch(__attributes_float3, offset);
- }
- else {
- return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
- }
- }
-}
-
-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 30b77ebd2eb..00000000000
--- a/intern/cycles/kernel/geom/geom_triangle_intersect.h
+++ /dev/null
@@ -1,309 +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(const KernelGlobals *kg,
- Intersection *isect,
- float3 P,
- float3 dir,
- float tmax,
- uint visibility,
- int object,
- int prim_addr)
-{
- const uint tri_vindex = kernel_tex_fetch(__prim_tri_index, prim_addr);
-#if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__)
- const ssef *ssef_verts = (ssef *)&kg->__prim_tri_verts.data[tri_vindex];
-#else
- const float4 tri_a = kernel_tex_fetch(__prim_tri_verts, tri_vindex + 0),
- tri_b = kernel_tex_fetch(__prim_tri_verts, tri_vindex + 1),
- tri_c = kernel_tex_fetch(__prim_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->prim = prim_addr;
- isect->object = object;
- 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(const KernelGlobals *kg,
- LocalIntersection *local_isect,
- float3 P,
- float3 dir,
- int object,
- int local_object,
- int prim_addr,
- float tmax,
- 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 uint tri_vindex = kernel_tex_fetch(__prim_tri_index, prim_addr);
-# if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__)
- const ssef *ssef_verts = (ssef *)&kg->__prim_tri_verts.data[tri_vindex];
-# else
- const float3 tri_a = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex + 0)),
- tri_b = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex + 1)),
- tri_c = float4_to_float3(kernel_tex_fetch(__prim_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. */
- Intersection *isect = &local_isect->hits[hit];
- isect->prim = prim_addr;
- isect->object = 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(__prim_tri_verts, tri_vindex + 0)),
- tri_b = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex + 1)),
- tri_c = float4_to_float3(kernel_tex_fetch(__prim_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(const KernelGlobals *kg,
- ShaderData *sd,
- float3 P,
- float3 D,
- float t,
- const int isect_object,
- const int isect_prim)
-{
-#ifdef __INTERSECTION_REFINE__
- if (isect_object != OBJECT_NONE) {
- 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(__prim_tri_index, isect_prim);
- const float4 tri_a = kernel_tex_fetch(__prim_tri_verts, tri_vindex + 0),
- tri_b = kernel_tex_fetch(__prim_tri_verts, tri_vindex + 1),
- tri_c = kernel_tex_fetch(__prim_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 (isect_object != OBJECT_NONE) {
- 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(const KernelGlobals *kg,
- 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 (isect_object != OBJECT_NONE) {
- 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(__prim_tri_index, isect_prim);
- const float4 tri_a = kernel_tex_fetch(__prim_tri_verts, tri_vindex + 0),
- tri_b = kernel_tex_fetch(__prim_tri_verts, tri_vindex + 1),
- tri_c = kernel_tex_fetch(__prim_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 (isect_object != OBJECT_NONE) {
- 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/geom_volume.h
deleted file mode 100644
index 2bcd7e56b5f..00000000000
--- a/intern/cycles/kernel/geom/geom_volume.h
+++ /dev/null
@@ -1,97 +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.
- */
-
-/* Volume Primitive
- *
- * Volumes are just regions inside meshes with the mesh surface as boundaries.
- * There isn't as much data to access as for surfaces, there is only a position
- * to do lookups in 3D voxel or procedural textures.
- *
- * 3D voxel textures can be assigned as attributes per mesh, which means the
- * same shader can be used for volume objects with different densities, etc. */
-
-#pragma once
-
-CCL_NAMESPACE_BEGIN
-
-#ifdef __VOLUME__
-
-/* Return position normalized to 0..1 in mesh bounds */
-
-ccl_device_inline float3 volume_normalized_position(const KernelGlobals *kg,
- const ShaderData *sd,
- float3 P)
-{
- /* todo: optimize this so it's just a single matrix multiplication when
- * possible (not motion blur), or perhaps even just translation + scale */
- const AttributeDescriptor desc = find_attribute(kg, sd, ATTR_STD_GENERATED_TRANSFORM);
-
- object_inverse_position_transform(kg, sd, &P);
-
- if (desc.offset != ATTR_STD_NOT_FOUND) {
- Transform tfm = primitive_attribute_matrix(kg, sd, desc);
- P = transform_point(&tfm, P);
- }
-
- return P;
-}
-
-ccl_device float volume_attribute_value_to_float(const float4 value)
-{
- return average(float4_to_float3(value));
-}
-
-ccl_device float volume_attribute_value_to_alpha(const float4 value)
-{
- return value.w;
-}
-
-ccl_device float3 volume_attribute_value_to_float3(const float4 value)
-{
- if (value.w > 1e-6f && value.w != 1.0f) {
- /* For RGBA colors, unpremultiply after interpolation. */
- return float4_to_float3(value) / value.w;
- }
- else {
- return float4_to_float3(value);
- }
-}
-
-ccl_device float4 volume_attribute_float4(const KernelGlobals *kg,
- const ShaderData *sd,
- const AttributeDescriptor desc)
-{
- if (desc.element & (ATTR_ELEMENT_OBJECT | ATTR_ELEMENT_MESH)) {
- return kernel_tex_fetch(__attributes_float3, desc.offset);
- }
- else if (desc.element == ATTR_ELEMENT_VOXEL) {
- /* todo: optimize this so we don't have to transform both here and in
- * kernel_tex_image_interp_3d when possible. Also could optimize for the
- * common case where transform is translation/scale only. */
- float3 P = sd->P;
- object_inverse_position_transform(kg, sd, &P);
- InterpolationType interp = (sd->flag & SD_VOLUME_CUBIC) ? INTERPOLATION_CUBIC :
- INTERPOLATION_NONE;
- return kernel_tex_image_interp_3d(kg, desc.offset, P, interp);
- }
- else {
- return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
- }
-}
-
-#endif
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/geom/motion_curve.h b/intern/cycles/kernel/geom/motion_curve.h
new file mode 100644
index 00000000000..8358c94360f
--- /dev/null
+++ b/intern/cycles/kernel/geom/motion_curve.h
@@ -0,0 +1,155 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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
+
+/* Motion Curve Primitive
+ *
+ * These are stored as regular curves, plus extra positions and radii at times
+ * other than the frame center. Computing the curve keys at a given ray time is
+ * a matter of interpolation of the two steps between which the ray time lies.
+ *
+ * The extra curve keys are stored as ATTR_STD_MOTION_VERTEX_POSITION.
+ */
+
+#ifdef __HAIR__
+
+ccl_device_inline void motion_curve_keys_for_step_linear(KernelGlobals kg,
+ int offset,
+ int numkeys,
+ int numsteps,
+ int step,
+ int k0,
+ int k1,
+ float4 keys[2])
+{
+ if (step == numsteps) {
+ /* center step: regular key location */
+ keys[0] = kernel_tex_fetch(__curve_keys, k0);
+ keys[1] = kernel_tex_fetch(__curve_keys, k1);
+ }
+ else {
+ /* center step is not stored in this array */
+ if (step > numsteps)
+ step--;
+
+ offset += step * numkeys;
+
+ keys[0] = kernel_tex_fetch(__attributes_float4, offset + k0);
+ keys[1] = kernel_tex_fetch(__attributes_float4, offset + k1);
+ }
+}
+
+/* return 2 curve key locations */
+ccl_device_inline void motion_curve_keys_linear(
+ KernelGlobals kg, int object, int prim, float time, int k0, int k1, float4 keys[2])
+{
+ /* get motion info */
+ int numsteps, numkeys;
+ object_motion_info(kg, object, &numsteps, NULL, &numkeys);
+
+ /* figure out which steps we need to fetch and their interpolation factor */
+ const int maxstep = numsteps * 2;
+ const int step = min((int)(time * maxstep), maxstep - 1);
+ const float t = time * maxstep - step;
+
+ /* find attribute */
+ const int offset = intersection_find_attribute(kg, object, ATTR_STD_MOTION_VERTEX_POSITION);
+ kernel_assert(offset != ATTR_STD_NOT_FOUND);
+
+ /* fetch key coordinates */
+ float4 next_keys[2];
+
+ motion_curve_keys_for_step_linear(kg, offset, numkeys, numsteps, step, k0, k1, keys);
+ motion_curve_keys_for_step_linear(kg, offset, numkeys, numsteps, step + 1, k0, k1, next_keys);
+
+ /* interpolate between steps */
+ keys[0] = (1.0f - t) * keys[0] + t * next_keys[0];
+ keys[1] = (1.0f - t) * keys[1] + t * next_keys[1];
+}
+
+ccl_device_inline void motion_curve_keys_for_step(KernelGlobals kg,
+ int offset,
+ int numkeys,
+ int numsteps,
+ int step,
+ int k0,
+ int k1,
+ int k2,
+ int k3,
+ float4 keys[4])
+{
+ if (step == numsteps) {
+ /* center step: regular key location */
+ keys[0] = kernel_tex_fetch(__curve_keys, k0);
+ keys[1] = kernel_tex_fetch(__curve_keys, k1);
+ keys[2] = kernel_tex_fetch(__curve_keys, k2);
+ keys[3] = kernel_tex_fetch(__curve_keys, k3);
+ }
+ else {
+ /* center step is not stored in this array */
+ if (step > numsteps)
+ step--;
+
+ offset += step * numkeys;
+
+ keys[0] = kernel_tex_fetch(__attributes_float4, offset + k0);
+ keys[1] = kernel_tex_fetch(__attributes_float4, offset + k1);
+ keys[2] = kernel_tex_fetch(__attributes_float4, offset + k2);
+ keys[3] = kernel_tex_fetch(__attributes_float4, offset + k3);
+ }
+}
+
+/* return 2 curve key locations */
+ccl_device_inline void motion_curve_keys(KernelGlobals kg,
+ int object,
+ int prim,
+ float time,
+ int k0,
+ int k1,
+ int k2,
+ int k3,
+ float4 keys[4])
+{
+ /* get motion info */
+ int numsteps, numkeys;
+ object_motion_info(kg, object, &numsteps, NULL, &numkeys);
+
+ /* figure out which steps we need to fetch and their interpolation factor */
+ const int maxstep = numsteps * 2;
+ const int step = min((int)(time * maxstep), maxstep - 1);
+ const float t = time * maxstep - step;
+
+ /* find attribute */
+ const int offset = intersection_find_attribute(kg, object, ATTR_STD_MOTION_VERTEX_POSITION);
+ kernel_assert(offset != ATTR_STD_NOT_FOUND);
+
+ /* fetch key coordinates */
+ float4 next_keys[4];
+
+ motion_curve_keys_for_step(kg, offset, numkeys, numsteps, step, k0, k1, k2, k3, keys);
+ motion_curve_keys_for_step(kg, offset, numkeys, numsteps, step + 1, k0, k1, k2, k3, next_keys);
+
+ /* interpolate between steps */
+ keys[0] = (1.0f - t) * keys[0] + t * next_keys[0];
+ keys[1] = (1.0f - t) * keys[1] + t * next_keys[1];
+ keys[2] = (1.0f - t) * keys[2] + t * next_keys[2];
+ keys[3] = (1.0f - t) * keys[3] + t * next_keys[3];
+}
+
+#endif
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/geom/motion_point.h b/intern/cycles/kernel/geom/motion_point.h
new file mode 100644
index 00000000000..d7ffc80c045
--- /dev/null
+++ b/intern/cycles/kernel/geom/motion_point.h
@@ -0,0 +1,74 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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
+
+/* Motion Point Primitive
+ *
+ * These are stored as regular points, plus extra positions and radii at times
+ * other than the frame center. Computing the point at a given ray time is
+ * a matter of interpolation of the two steps between which the ray time lies.
+ *
+ * The extra points are stored as ATTR_STD_MOTION_VERTEX_POSITION.
+ */
+
+#ifdef __POINTCLOUD__
+
+ccl_device_inline float4
+motion_point_for_step(KernelGlobals kg, int offset, int numkeys, int numsteps, int step, int prim)
+{
+ if (step == numsteps) {
+ /* center step: regular key location */
+ return kernel_tex_fetch(__points, prim);
+ }
+ else {
+ /* center step is not stored in this array */
+ if (step > numsteps)
+ step--;
+
+ offset += step * numkeys;
+
+ return kernel_tex_fetch(__attributes_float4, offset + prim);
+ }
+}
+
+/* return 2 point key locations */
+ccl_device_inline float4 motion_point(KernelGlobals kg, int object, int prim, float time)
+{
+ /* get motion info */
+ int numsteps, numkeys;
+ object_motion_info(kg, object, &numsteps, NULL, &numkeys);
+
+ /* 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 key coordinates */
+ float4 point = motion_point_for_step(kg, offset, numkeys, numsteps, step, prim);
+ float4 next_point = motion_point_for_step(kg, offset, numkeys, numsteps, step + 1, prim);
+
+ /* interpolate between steps */
+ return (1.0f - t) * point + t * next_point;
+}
+
+#endif
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/geom/motion_triangle.h b/intern/cycles/kernel/geom/motion_triangle.h
new file mode 100644
index 00000000000..bd62325eaf2
--- /dev/null
+++ b/intern/cycles/kernel/geom/motion_triangle.h
@@ -0,0 +1,201 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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] = kernel_tex_fetch(__tri_verts, tri_vindex.w + 0);
+ verts[1] = kernel_tex_fetch(__tri_verts, tri_vindex.w + 1);
+ verts[2] = 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] = kernel_tex_fetch(__attributes_float3, offset + tri_vindex.x);
+ verts[1] = kernel_tex_fetch(__attributes_float3, offset + tri_vindex.y);
+ verts[2] = 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] = kernel_tex_fetch(__tri_vnormal, tri_vindex.x);
+ normals[1] = kernel_tex_fetch(__tri_vnormal, tri_vindex.y);
+ normals[2] = 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] = kernel_tex_fetch(__attributes_float3, offset + tri_vindex.x);
+ normals[1] = kernel_tex_fetch(__attributes_float3, offset + tri_vindex.y);
+ normals[2] = 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 void motion_triangle_vertices_and_normals(
+ KernelGlobals kg, int object, int prim, float time, float3 verts[3], float3 normals[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];
+
+ /* Compute smooth normal. */
+
+ /* Find attribute. */
+ offset = intersection_find_attribute(kg, object, ATTR_STD_MOTION_VERTEX_NORMAL);
+ kernel_assert(offset != ATTR_STD_NOT_FOUND);
+
+ /* Fetch vertex coordinates. */
+ float3 next_normals[3];
+ 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];
+}
+
+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/motion_triangle_intersect.h b/intern/cycles/kernel/geom/motion_triangle_intersect.h
new file mode 100644
index 00000000000..a11cb88385b
--- /dev/null
+++ b/intern/cycles/kernel/geom/motion_triangle_intersect.h
@@ -0,0 +1,176 @@
+/*
+ * 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.
+ */
+
+/* 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
+
+CCL_NAMESPACE_BEGIN
+
+/**
+ * Use the barycentric coordinates to get the intersection location
+ */
+ccl_device_inline float3 motion_triangle_point_from_uv(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ const int isect_object,
+ const int isect_prim,
+ const float u,
+ const float v,
+ float3 verts[3])
+{
+ float w = 1.0f - u - v;
+ float3 P = u * verts[0] + v * verts[1] + w * verts[2];
+
+ if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
+ const Transform tfm = object_get_transform(kg, sd);
+ P = transform_point(&tfm, P);
+ }
+
+ return P;
+}
+
+/* Ray intersection. We simply compute the vertex positions at the given ray
+ * time and do a ray intersection with the resulting triangle.
+ */
+
+ccl_device_inline bool motion_triangle_intersect(KernelGlobals kg,
+ ccl_private Intersection *isect,
+ float3 P,
+ float3 dir,
+ float tmax,
+ float time,
+ uint visibility,
+ int object,
+ int prim,
+ int prim_addr)
+{
+ /* Get vertex locations for intersection. */
+ float3 verts[3];
+ motion_triangle_vertices(kg, object, prim, time, verts);
+ /* Ray-triangle intersection, unoptimized. */
+ float t, u, v;
+ if (ray_triangle_intersect(P, dir, tmax, verts[0], verts[1], verts[2], &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->t = t;
+ isect->u = u;
+ isect->v = v;
+ isect->prim = prim;
+ isect->object = object;
+ isect->type = PRIMITIVE_MOTION_TRIANGLE;
+ return true;
+ }
+ }
+ return false;
+}
+
+/* Special ray intersection routines for local intersections. 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 motion_triangle_intersect_local(KernelGlobals kg,
+ ccl_private LocalIntersection *local_isect,
+ float3 P,
+ float3 dir,
+ float time,
+ int object,
+ int prim,
+ int prim_addr,
+ float tmax,
+ ccl_private uint *lcg_state,
+ int max_hits)
+{
+ /* Get vertex locations for intersection. */
+ float3 verts[3];
+ motion_triangle_vertices(kg, object, prim, time, verts);
+ /* Ray-triangle intersection, unoptimized. */
+ float t, u, v;
+ if (!ray_triangle_intersect(P, dir, tmax, verts[0], verts[1], verts[2], &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->t = t;
+ isect->u = u;
+ isect->v = v;
+ isect->prim = prim;
+ isect->object = object;
+ isect->type = PRIMITIVE_MOTION_TRIANGLE;
+
+ /* Record geometric normal. */
+ local_isect->Ng[hit] = normalize(cross(verts[1] - verts[0], verts[2] - verts[0]));
+
+ return false;
+}
+#endif /* __BVH_LOCAL__ */
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/geom/motion_triangle_shader.h b/intern/cycles/kernel/geom/motion_triangle_shader.h
new file mode 100644
index 00000000000..15730c83969
--- /dev/null
+++ b/intern/cycles/kernel/geom/motion_triangle_shader.h
@@ -0,0 +1,109 @@
+/*
+ * 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.
+ */
+
+/* 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
+
+CCL_NAMESPACE_BEGIN
+
+/* Setup of motion triangle specific parts of ShaderData, moved into this one
+ * function to more easily share computation of interpolated positions and
+ * normals */
+
+/* return 3 triangle vertex normals */
+ccl_device_noinline void motion_triangle_shader_setup(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ const float3 P,
+ const float3 D,
+ const float ray_t,
+ const int isect_object,
+ const int isect_prim,
+ bool is_local)
+{
+ /* Get shader. */
+ sd->shader = kernel_tex_fetch(__tri_shader, sd->prim);
+ /* Get motion info. */
+ /* TODO(sergey): This logic is really similar to motion_triangle_vertices(),
+ * can we de-duplicate something here?
+ */
+ int numsteps, numverts;
+ object_motion_info(kg, sd->object, &numsteps, &numverts, NULL);
+ /* Figure out which steps we need to fetch and their interpolation factor. */
+ int maxstep = numsteps * 2;
+ int step = min((int)(sd->time * maxstep), maxstep - 1);
+ float t = sd->time * maxstep - step;
+ /* Find attribute. */
+ int offset = intersection_find_attribute(kg, sd->object, ATTR_STD_MOTION_VERTEX_POSITION);
+ kernel_assert(offset != ATTR_STD_NOT_FOUND);
+ /* Fetch vertex coordinates. */
+ float3 verts[3], next_verts[3];
+ uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, sd->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];
+ /* Compute refined position. */
+ sd->P = motion_triangle_point_from_uv(kg, sd, isect_object, isect_prim, sd->u, sd->v, verts);
+ /* Compute face normal. */
+ float3 Ng;
+ if (sd->object_flag & SD_OBJECT_NEGATIVE_SCALE_APPLIED) {
+ Ng = normalize(cross(verts[2] - verts[0], verts[1] - verts[0]));
+ }
+ else {
+ Ng = normalize(cross(verts[1] - verts[0], verts[2] - verts[0]));
+ }
+ sd->Ng = Ng;
+ sd->N = Ng;
+ /* Compute derivatives of P w.r.t. uv. */
+#ifdef __DPDU__
+ sd->dPdu = (verts[0] - verts[2]);
+ sd->dPdv = (verts[1] - verts[2]);
+#endif
+ /* Compute smooth normal. */
+ if (sd->shader & SHADER_SMOOTH_NORMAL) {
+ /* Find attribute. */
+ int offset = intersection_find_attribute(kg, sd->object, ATTR_STD_MOTION_VERTEX_NORMAL);
+ kernel_assert(offset != ATTR_STD_NOT_FOUND);
+ /* Fetch vertex coordinates. */
+ float3 normals[3], next_normals[3];
+ 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 u = sd->u;
+ float v = sd->v;
+ float w = 1.0f - u - v;
+ sd->N = (u * normals[0] + v * normals[1] + w * normals[2]);
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/geom/object.h b/intern/cycles/kernel/geom/object.h
new file mode 100644
index 00000000000..34a9d639d9d
--- /dev/null
+++ b/intern/cycles/kernel/geom/object.h
@@ -0,0 +1,600 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* Object Primitive
+ *
+ * All mesh and curve primitives are part of an object. The same mesh and curves
+ * may be instanced multiple times by different objects.
+ *
+ * If the mesh is not instanced multiple times, the object will not be explicitly
+ * stored as a primitive in the BVH, rather the bare triangles are curved are
+ * directly primitives in the BVH with world space locations applied, and the object
+ * ID is looked up afterwards. */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/* Object attributes, for now a fixed size and contents */
+
+enum ObjectTransform {
+ OBJECT_TRANSFORM = 0,
+ OBJECT_INVERSE_TRANSFORM = 1,
+};
+
+enum ObjectVectorTransform { OBJECT_PASS_MOTION_PRE = 0, OBJECT_PASS_MOTION_POST = 1 };
+
+/* Object to world space transformation */
+
+ccl_device_inline Transform object_fetch_transform(KernelGlobals kg,
+ int object,
+ enum ObjectTransform type)
+{
+ if (type == OBJECT_INVERSE_TRANSFORM) {
+ return kernel_tex_fetch(__objects, object).itfm;
+ }
+ else {
+ return kernel_tex_fetch(__objects, object).tfm;
+ }
+}
+
+/* Lamp to world space transformation */
+
+ccl_device_inline Transform lamp_fetch_transform(KernelGlobals kg, int lamp, bool inverse)
+{
+ if (inverse) {
+ return kernel_tex_fetch(__lights, lamp).itfm;
+ }
+ else {
+ return kernel_tex_fetch(__lights, lamp).tfm;
+ }
+}
+
+/* Object to world space transformation for motion vectors */
+
+ccl_device_inline Transform object_fetch_motion_pass_transform(KernelGlobals kg,
+ int object,
+ enum ObjectVectorTransform type)
+{
+ int offset = object * OBJECT_MOTION_PASS_SIZE + (int)type;
+ return kernel_tex_fetch(__object_motion_pass, offset);
+}
+
+/* Motion blurred object transformations */
+
+#ifdef __OBJECT_MOTION__
+ccl_device_inline Transform object_fetch_transform_motion(KernelGlobals kg, int object, float time)
+{
+ const uint motion_offset = kernel_tex_fetch(__objects, object).motion_offset;
+ ccl_global const DecomposedTransform *motion = &kernel_tex_fetch(__object_motion, motion_offset);
+ const uint num_steps = kernel_tex_fetch(__objects, object).numsteps * 2 + 1;
+
+ Transform tfm;
+ transform_motion_array_interpolate(&tfm, motion, num_steps, time);
+
+ return tfm;
+}
+
+ccl_device_inline Transform object_fetch_transform_motion_test(KernelGlobals kg,
+ int object,
+ float time,
+ ccl_private Transform *itfm)
+{
+ int object_flag = kernel_tex_fetch(__object_flag, object);
+ if (object_flag & SD_OBJECT_MOTION) {
+ /* if we do motion blur */
+ Transform tfm = object_fetch_transform_motion(kg, object, time);
+
+ if (itfm)
+ *itfm = transform_quick_inverse(tfm);
+
+ return tfm;
+ }
+ else {
+ Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
+ if (itfm)
+ *itfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
+
+ return tfm;
+ }
+}
+#endif
+
+/* Get transform matrix for shading point. */
+
+ccl_device_inline Transform object_get_transform(KernelGlobals kg,
+ ccl_private const ShaderData *sd)
+{
+#ifdef __OBJECT_MOTION__
+ return (sd->object_flag & SD_OBJECT_MOTION) ?
+ sd->ob_tfm_motion :
+ object_fetch_transform(kg, sd->object, OBJECT_TRANSFORM);
+#else
+ return object_fetch_transform(kg, sd->object, OBJECT_TRANSFORM);
+#endif
+}
+
+ccl_device_inline Transform object_get_inverse_transform(KernelGlobals kg,
+ ccl_private const ShaderData *sd)
+{
+#ifdef __OBJECT_MOTION__
+ return (sd->object_flag & SD_OBJECT_MOTION) ?
+ sd->ob_itfm_motion :
+ object_fetch_transform(kg, sd->object, OBJECT_INVERSE_TRANSFORM);
+#else
+ return object_fetch_transform(kg, sd->object, OBJECT_INVERSE_TRANSFORM);
+#endif
+}
+/* Transform position from object to world space */
+
+ccl_device_inline void object_position_transform(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ ccl_private float3 *P)
+{
+#ifdef __OBJECT_MOTION__
+ if (sd->object_flag & SD_OBJECT_MOTION) {
+ *P = transform_point_auto(&sd->ob_tfm_motion, *P);
+ return;
+ }
+#endif
+
+ Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_TRANSFORM);
+ *P = transform_point(&tfm, *P);
+}
+
+/* Transform position from world to object space */
+
+ccl_device_inline void object_inverse_position_transform(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ ccl_private float3 *P)
+{
+#ifdef __OBJECT_MOTION__
+ if (sd->object_flag & SD_OBJECT_MOTION) {
+ *P = transform_point_auto(&sd->ob_itfm_motion, *P);
+ return;
+ }
+#endif
+
+ Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_INVERSE_TRANSFORM);
+ *P = transform_point(&tfm, *P);
+}
+
+/* Transform normal from world to object space */
+
+ccl_device_inline void object_inverse_normal_transform(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ ccl_private float3 *N)
+{
+#ifdef __OBJECT_MOTION__
+ if (sd->object_flag & SD_OBJECT_MOTION) {
+ if ((sd->object != OBJECT_NONE) || (sd->type == PRIMITIVE_LAMP)) {
+ *N = normalize(transform_direction_transposed_auto(&sd->ob_tfm_motion, *N));
+ }
+ return;
+ }
+#endif
+
+ if (sd->object != OBJECT_NONE) {
+ Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_TRANSFORM);
+ *N = normalize(transform_direction_transposed(&tfm, *N));
+ }
+ else if (sd->type == PRIMITIVE_LAMP) {
+ Transform tfm = lamp_fetch_transform(kg, sd->lamp, false);
+ *N = normalize(transform_direction_transposed(&tfm, *N));
+ }
+}
+
+/* Transform normal from object to world space */
+
+ccl_device_inline void object_normal_transform(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ ccl_private float3 *N)
+{
+#ifdef __OBJECT_MOTION__
+ if (sd->object_flag & SD_OBJECT_MOTION) {
+ *N = normalize(transform_direction_transposed_auto(&sd->ob_itfm_motion, *N));
+ return;
+ }
+#endif
+
+ Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_INVERSE_TRANSFORM);
+ *N = normalize(transform_direction_transposed(&tfm, *N));
+}
+
+/* Transform direction vector from object to world space */
+
+ccl_device_inline void object_dir_transform(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ ccl_private float3 *D)
+{
+#ifdef __OBJECT_MOTION__
+ if (sd->object_flag & SD_OBJECT_MOTION) {
+ *D = transform_direction_auto(&sd->ob_tfm_motion, *D);
+ return;
+ }
+#endif
+
+ Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_TRANSFORM);
+ *D = transform_direction(&tfm, *D);
+}
+
+/* Transform direction vector from world to object space */
+
+ccl_device_inline void object_inverse_dir_transform(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ ccl_private float3 *D)
+{
+#ifdef __OBJECT_MOTION__
+ if (sd->object_flag & SD_OBJECT_MOTION) {
+ *D = transform_direction_auto(&sd->ob_itfm_motion, *D);
+ return;
+ }
+#endif
+
+ const Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_INVERSE_TRANSFORM);
+ *D = transform_direction(&tfm, *D);
+}
+
+/* Object center position */
+
+ccl_device_inline float3 object_location(KernelGlobals kg, ccl_private const ShaderData *sd)
+{
+ if (sd->object == OBJECT_NONE)
+ return make_float3(0.0f, 0.0f, 0.0f);
+
+#ifdef __OBJECT_MOTION__
+ if (sd->object_flag & SD_OBJECT_MOTION) {
+ return make_float3(sd->ob_tfm_motion.x.w, sd->ob_tfm_motion.y.w, sd->ob_tfm_motion.z.w);
+ }
+#endif
+
+ Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_TRANSFORM);
+ return make_float3(tfm.x.w, tfm.y.w, tfm.z.w);
+}
+
+/* Color of the object */
+
+ccl_device_inline float3 object_color(KernelGlobals kg, int object)
+{
+ if (object == OBJECT_NONE)
+ return make_float3(0.0f, 0.0f, 0.0f);
+
+ ccl_global const KernelObject *kobject = &kernel_tex_fetch(__objects, object);
+ return make_float3(kobject->color[0], kobject->color[1], kobject->color[2]);
+}
+
+/* Pass ID number of object */
+
+ccl_device_inline float object_pass_id(KernelGlobals kg, int object)
+{
+ if (object == OBJECT_NONE)
+ return 0.0f;
+
+ return kernel_tex_fetch(__objects, object).pass_id;
+}
+
+/* Per lamp random number for shader variation */
+
+ccl_device_inline float lamp_random_number(KernelGlobals kg, int lamp)
+{
+ if (lamp == LAMP_NONE)
+ return 0.0f;
+
+ return kernel_tex_fetch(__lights, lamp).random;
+}
+
+/* Per object random number for shader variation */
+
+ccl_device_inline float object_random_number(KernelGlobals kg, int object)
+{
+ if (object == OBJECT_NONE)
+ return 0.0f;
+
+ return kernel_tex_fetch(__objects, object).random_number;
+}
+
+/* Particle ID from which this object was generated */
+
+ccl_device_inline int object_particle_id(KernelGlobals kg, int object)
+{
+ if (object == OBJECT_NONE)
+ return 0;
+
+ return kernel_tex_fetch(__objects, object).particle_index;
+}
+
+/* Generated texture coordinate on surface from where object was instanced */
+
+ccl_device_inline float3 object_dupli_generated(KernelGlobals kg, int object)
+{
+ if (object == OBJECT_NONE)
+ return make_float3(0.0f, 0.0f, 0.0f);
+
+ ccl_global const KernelObject *kobject = &kernel_tex_fetch(__objects, object);
+ return make_float3(
+ kobject->dupli_generated[0], kobject->dupli_generated[1], kobject->dupli_generated[2]);
+}
+
+/* UV texture coordinate on surface from where object was instanced */
+
+ccl_device_inline float3 object_dupli_uv(KernelGlobals kg, int object)
+{
+ if (object == OBJECT_NONE)
+ return make_float3(0.0f, 0.0f, 0.0f);
+
+ ccl_global const KernelObject *kobject = &kernel_tex_fetch(__objects, object);
+ return make_float3(kobject->dupli_uv[0], kobject->dupli_uv[1], 0.0f);
+}
+
+/* Information about mesh for motion blurred triangles and curves */
+
+ccl_device_inline void object_motion_info(KernelGlobals kg,
+ int object,
+ ccl_private int *numsteps,
+ ccl_private int *numverts,
+ ccl_private int *numkeys)
+{
+ if (numkeys) {
+ *numkeys = kernel_tex_fetch(__objects, object).numkeys;
+ }
+
+ if (numsteps)
+ *numsteps = kernel_tex_fetch(__objects, object).numsteps;
+ if (numverts)
+ *numverts = kernel_tex_fetch(__objects, object).numverts;
+}
+
+/* Offset to an objects patch map */
+
+ccl_device_inline uint object_patch_map_offset(KernelGlobals kg, int object)
+{
+ if (object == OBJECT_NONE)
+ return 0;
+
+ return kernel_tex_fetch(__objects, object).patch_map_offset;
+}
+
+/* Volume step size */
+
+ccl_device_inline float object_volume_density(KernelGlobals kg, int object)
+{
+ if (object == OBJECT_NONE) {
+ return 1.0f;
+ }
+
+ return kernel_tex_fetch(__objects, object).volume_density;
+}
+
+ccl_device_inline float object_volume_step_size(KernelGlobals kg, int object)
+{
+ if (object == OBJECT_NONE) {
+ return kernel_data.background.volume_step_size;
+ }
+
+ return kernel_tex_fetch(__object_volume_step, object);
+}
+
+/* Pass ID for shader */
+
+ccl_device int shader_pass_id(KernelGlobals kg, ccl_private const ShaderData *sd)
+{
+ return kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).pass_id;
+}
+
+/* Cryptomatte ID */
+
+ccl_device_inline float object_cryptomatte_id(KernelGlobals kg, int object)
+{
+ if (object == OBJECT_NONE)
+ return 0.0f;
+
+ return kernel_tex_fetch(__objects, object).cryptomatte_object;
+}
+
+ccl_device_inline float object_cryptomatte_asset_id(KernelGlobals kg, int object)
+{
+ if (object == OBJECT_NONE)
+ return 0;
+
+ return kernel_tex_fetch(__objects, object).cryptomatte_asset;
+}
+
+/* Particle data from which object was instanced */
+
+ccl_device_inline uint particle_index(KernelGlobals kg, int particle)
+{
+ return kernel_tex_fetch(__particles, particle).index;
+}
+
+ccl_device float particle_age(KernelGlobals kg, int particle)
+{
+ return kernel_tex_fetch(__particles, particle).age;
+}
+
+ccl_device float particle_lifetime(KernelGlobals kg, int particle)
+{
+ return kernel_tex_fetch(__particles, particle).lifetime;
+}
+
+ccl_device float particle_size(KernelGlobals kg, int particle)
+{
+ return kernel_tex_fetch(__particles, particle).size;
+}
+
+ccl_device float4 particle_rotation(KernelGlobals kg, int particle)
+{
+ return kernel_tex_fetch(__particles, particle).rotation;
+}
+
+ccl_device float3 particle_location(KernelGlobals kg, int particle)
+{
+ return float4_to_float3(kernel_tex_fetch(__particles, particle).location);
+}
+
+ccl_device float3 particle_velocity(KernelGlobals kg, int particle)
+{
+ return float4_to_float3(kernel_tex_fetch(__particles, particle).velocity);
+}
+
+ccl_device float3 particle_angular_velocity(KernelGlobals kg, int particle)
+{
+ return float4_to_float3(kernel_tex_fetch(__particles, particle).angular_velocity);
+}
+
+/* Object intersection in BVH */
+
+ccl_device_inline float3 bvh_clamp_direction(float3 dir)
+{
+ const float ooeps = 8.271806E-25f;
+ return make_float3((fabsf(dir.x) > ooeps) ? dir.x : copysignf(ooeps, dir.x),
+ (fabsf(dir.y) > ooeps) ? dir.y : copysignf(ooeps, dir.y),
+ (fabsf(dir.z) > ooeps) ? dir.z : copysignf(ooeps, dir.z));
+}
+
+ccl_device_inline float3 bvh_inverse_direction(float3 dir)
+{
+ return rcp(dir);
+}
+
+/* Transform ray into object space to enter static object in BVH */
+
+ccl_device_inline float bvh_instance_push(KernelGlobals kg,
+ int object,
+ ccl_private const Ray *ray,
+ ccl_private float3 *P,
+ ccl_private float3 *dir,
+ ccl_private float3 *idir)
+{
+ Transform tfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
+
+ *P = transform_point(&tfm, ray->P);
+
+ float len;
+ *dir = bvh_clamp_direction(normalize_len(transform_direction(&tfm, ray->D), &len));
+ *idir = bvh_inverse_direction(*dir);
+
+ return len;
+}
+
+/* Transform ray to exit static object in BVH. */
+
+ccl_device_inline float bvh_instance_pop(KernelGlobals kg,
+ int object,
+ ccl_private const Ray *ray,
+ ccl_private float3 *P,
+ ccl_private float3 *dir,
+ ccl_private float3 *idir,
+ float t)
+{
+ if (t != FLT_MAX) {
+ Transform tfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
+ t /= len(transform_direction(&tfm, ray->D));
+ }
+
+ *P = ray->P;
+ *dir = bvh_clamp_direction(ray->D);
+ *idir = bvh_inverse_direction(*dir);
+
+ return t;
+}
+
+/* Same as above, but returns scale factor to apply to multiple intersection distances */
+
+ccl_device_inline void bvh_instance_pop_factor(KernelGlobals kg,
+ int object,
+ ccl_private const Ray *ray,
+ ccl_private float3 *P,
+ ccl_private float3 *dir,
+ ccl_private float3 *idir,
+ ccl_private float *t_fac)
+{
+ Transform tfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
+ *t_fac = 1.0f / len(transform_direction(&tfm, ray->D));
+
+ *P = ray->P;
+ *dir = bvh_clamp_direction(ray->D);
+ *idir = bvh_inverse_direction(*dir);
+}
+
+#ifdef __OBJECT_MOTION__
+/* Transform ray into object space to enter motion blurred object in BVH */
+
+ccl_device_inline float bvh_instance_motion_push(KernelGlobals kg,
+ int object,
+ ccl_private const Ray *ray,
+ ccl_private float3 *P,
+ ccl_private float3 *dir,
+ ccl_private float3 *idir,
+ ccl_private Transform *itfm)
+{
+ object_fetch_transform_motion_test(kg, object, ray->time, itfm);
+
+ *P = transform_point(itfm, ray->P);
+
+ float len;
+ *dir = bvh_clamp_direction(normalize_len(transform_direction(itfm, ray->D), &len));
+ *idir = bvh_inverse_direction(*dir);
+
+ return len;
+}
+
+/* Transform ray to exit motion blurred object in BVH. */
+
+ccl_device_inline float bvh_instance_motion_pop(KernelGlobals kg,
+ int object,
+ ccl_private const Ray *ray,
+ ccl_private float3 *P,
+ ccl_private float3 *dir,
+ ccl_private float3 *idir,
+ float t,
+ ccl_private Transform *itfm)
+{
+ if (t != FLT_MAX) {
+ t /= len(transform_direction(itfm, ray->D));
+ }
+
+ *P = ray->P;
+ *dir = bvh_clamp_direction(ray->D);
+ *idir = bvh_inverse_direction(*dir);
+
+ return t;
+}
+
+/* Same as above, but returns scale factor to apply to multiple intersection distances */
+
+ccl_device_inline void bvh_instance_motion_pop_factor(KernelGlobals kg,
+ int object,
+ ccl_private const Ray *ray,
+ ccl_private float3 *P,
+ ccl_private float3 *dir,
+ ccl_private float3 *idir,
+ ccl_private float *t_fac,
+ ccl_private Transform *itfm)
+{
+ *t_fac = 1.0f / len(transform_direction(itfm, ray->D));
+ *P = ray->P;
+ *dir = bvh_clamp_direction(ray->D);
+ *idir = bvh_inverse_direction(*dir);
+}
+
+#endif
+
+/* TODO: This can be removed when we know if no devices will require explicit
+ * address space qualifiers for this case. */
+
+#define object_position_transform_auto object_position_transform
+#define object_dir_transform_auto object_dir_transform
+#define object_normal_transform_auto object_normal_transform
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/geom/patch.h b/intern/cycles/kernel/geom/patch.h
new file mode 100644
index 00000000000..432618aa243
--- /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 = 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_float4, 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/point.h b/intern/cycles/kernel/geom/point.h
new file mode 100644
index 00000000000..545b5c7fa43
--- /dev/null
+++ b/intern/cycles/kernel/geom/point.h
@@ -0,0 +1,175 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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
+
+/* Point Primitive
+ *
+ * Point primitive for rendering point clouds.
+ */
+
+#ifdef __POINTCLOUD__
+
+/* Reading attributes on various point elements */
+
+ccl_device float point_attribute_float(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ const AttributeDescriptor desc,
+ ccl_private float *dx,
+ ccl_private float *dy)
+{
+# ifdef __RAY_DIFFERENTIALS__
+ if (dx)
+ *dx = 0.0f;
+ if (dy)
+ *dy = 0.0f;
+# endif
+
+ if (desc.element == ATTR_ELEMENT_VERTEX) {
+ return kernel_tex_fetch(__attributes_float, desc.offset + sd->prim);
+ }
+ else {
+ return 0.0f;
+ }
+}
+
+ccl_device float2 point_attribute_float2(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ const AttributeDescriptor desc,
+ ccl_private float2 *dx,
+ ccl_private float2 *dy)
+{
+# ifdef __RAY_DIFFERENTIALS__
+ if (dx)
+ *dx = make_float2(0.0f, 0.0f);
+ if (dy)
+ *dy = make_float2(0.0f, 0.0f);
+# endif
+
+ if (desc.element == ATTR_ELEMENT_VERTEX) {
+ return kernel_tex_fetch(__attributes_float2, desc.offset + sd->prim);
+ }
+ else {
+ return make_float2(0.0f, 0.0f);
+ }
+}
+
+ccl_device float3 point_attribute_float3(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ const AttributeDescriptor desc,
+ ccl_private float3 *dx,
+ ccl_private float3 *dy)
+{
+# ifdef __RAY_DIFFERENTIALS__
+ if (dx)
+ *dx = make_float3(0.0f, 0.0f, 0.0f);
+ if (dy)
+ *dy = make_float3(0.0f, 0.0f, 0.0f);
+# endif
+
+ if (desc.element == ATTR_ELEMENT_VERTEX) {
+ return kernel_tex_fetch(__attributes_float3, desc.offset + sd->prim);
+ }
+ else {
+ return make_float3(0.0f, 0.0f, 0.0f);
+ }
+}
+
+ccl_device float4 point_attribute_float4(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ const AttributeDescriptor desc,
+ ccl_private float4 *dx,
+ ccl_private float4 *dy)
+{
+# ifdef __RAY_DIFFERENTIALS__
+ 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);
+# endif
+
+ if (desc.element == ATTR_ELEMENT_VERTEX) {
+ return kernel_tex_fetch(__attributes_float4, desc.offset + sd->prim);
+ }
+ else {
+ return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ }
+}
+
+/* Point position */
+
+ccl_device float3 point_position(KernelGlobals kg, ccl_private const ShaderData *sd)
+{
+ if (sd->type & PRIMITIVE_POINT) {
+ /* World space center. */
+ float3 P = (sd->type & PRIMITIVE_MOTION) ?
+ float4_to_float3(motion_point(kg, sd->object, sd->prim, sd->time)) :
+ float4_to_float3(kernel_tex_fetch(__points, sd->prim));
+
+ if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
+ object_position_transform(kg, sd, &P);
+ }
+
+ return P;
+ }
+
+ return zero_float3();
+}
+
+/* Point radius */
+
+ccl_device float point_radius(KernelGlobals kg, ccl_private const ShaderData *sd)
+{
+ if (sd->type & PRIMITIVE_POINT) {
+ /* World space radius. */
+ const float r = kernel_tex_fetch(__points, sd->prim).w;
+
+ if (sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED) {
+ return r;
+ }
+ else {
+ float3 dir = make_float3(r, r, r);
+ object_dir_transform(kg, sd, &dir);
+ return average(dir);
+ }
+ }
+
+ return 0.0f;
+}
+
+/* Point random */
+
+ccl_device float point_random(KernelGlobals kg, ccl_private const ShaderData *sd)
+{
+ if (sd->type & PRIMITIVE_POINT) {
+ const AttributeDescriptor desc = find_attribute(kg, sd, ATTR_STD_POINT_RANDOM);
+ return (desc.offset != ATTR_STD_NOT_FOUND) ? point_attribute_float(kg, sd, desc, NULL, NULL) :
+ 0.0f;
+ }
+ return 0.0f;
+}
+
+/* Point location for motion pass, linear interpolation between keys and
+ * ignoring radius because we do the same for the motion keys */
+
+ccl_device float3 point_motion_center_location(KernelGlobals kg, ccl_private const ShaderData *sd)
+{
+ return float4_to_float3(kernel_tex_fetch(__points, sd->prim));
+}
+
+#endif /* __POINTCLOUD__ */
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/geom/point_intersect.h b/intern/cycles/kernel/geom/point_intersect.h
new file mode 100644
index 00000000000..757c8b81efa
--- /dev/null
+++ b/intern/cycles/kernel/geom/point_intersect.h
@@ -0,0 +1,128 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Based on Embree code, copyright 2009-2020 Intel Corporation.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/* Point primitive intersection functions. */
+
+#ifdef __POINTCLOUD__
+
+ccl_device_forceinline bool point_intersect_test(
+ const float4 point, const float3 P, const float3 dir, const float tmax, ccl_private float *t)
+{
+ const float3 center = float4_to_float3(point);
+ const float radius = point.w;
+
+ const float rd2 = 1.0f / dot(dir, dir);
+
+ const float3 c0 = center - P;
+ const float projC0 = dot(c0, dir) * rd2;
+ const float3 perp = c0 - projC0 * dir;
+ const float l2 = dot(perp, perp);
+ const float r2 = radius * radius;
+ if (!(l2 <= r2)) {
+ return false;
+ }
+
+ const float td = sqrt((r2 - l2) * rd2);
+ const float t_front = projC0 - td;
+ const bool valid_front = (0.0f <= t_front) & (t_front <= tmax);
+
+ /* Always back-face culling for now. */
+# if 0
+ const float t_back = projC0 + td;
+ const bool valid_back = (0.0f <= t_back) & (t_back <= tmax);
+
+ /* check if there is a first hit */
+ const bool valid_first = valid_front | valid_back;
+ if (!valid_first) {
+ return false;
+ }
+
+ *t = (valid_front) ? t_front : t_back;
+ return true;
+# else
+ if (!valid_front) {
+ return false;
+ }
+ *t = t_front;
+ return true;
+# endif
+}
+
+ccl_device_forceinline bool point_intersect(KernelGlobals kg,
+ ccl_private Intersection *isect,
+ const float3 P,
+ const float3 dir,
+ const float tmax,
+ const int object,
+ const int prim,
+ const float time,
+ const int type)
+{
+ const float4 point = (type & PRIMITIVE_MOTION) ? motion_point(kg, object, prim, time) :
+ kernel_tex_fetch(__points, prim);
+
+ if (!point_intersect_test(point, P, dir, tmax, &isect->t)) {
+ return false;
+ }
+
+ isect->prim = prim;
+ isect->object = object;
+ isect->type = type;
+ isect->u = 0.0f;
+ isect->v = 0.0f;
+ return true;
+}
+
+ccl_device_inline void point_shader_setup(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private const Intersection *isect,
+ ccl_private const Ray *ray)
+{
+ sd->shader = kernel_tex_fetch(__points_shader, isect->prim);
+ sd->P = ray->P + ray->D * isect->t;
+
+ /* Texture coordinates, zero for now. */
+# ifdef __UV__
+ sd->u = isect->u;
+ sd->v = isect->v;
+# endif
+
+ /* Compute point center for normal. */
+ float3 center = float4_to_float3((isect->type & PRIMITIVE_MOTION) ?
+ motion_point(kg, sd->object, sd->prim, sd->time) :
+ kernel_tex_fetch(__points, sd->prim));
+ if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
+ object_position_transform_auto(kg, sd, &center);
+ }
+
+ /* Normal */
+ sd->Ng = normalize(sd->P - center);
+ sd->N = sd->Ng;
+
+# ifdef __DPDU__
+ /* dPdu/dPdv */
+ sd->dPdu = make_float3(0.0f, 0.0f, 0.0f);
+ sd->dPdv = make_float3(0.0f, 0.0f, 0.0f);
+# endif
+}
+
+#endif
+
+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..2e8e0cda6f1
--- /dev/null
+++ b/intern/cycles/kernel/geom/primitive.h
@@ -0,0 +1,399 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_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_CURVE) {
+ return curve_attribute_float(kg, sd, desc, dx, dy);
+ }
+#endif
+#ifdef __POINTCLOUD__
+ else if (sd->type & PRIMITIVE_POINT) {
+ return point_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_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_CURVE) {
+ return curve_attribute_float2(kg, sd, desc, dx, dy);
+ }
+#endif
+#ifdef __POINTCLOUD__
+ else if (sd->type & PRIMITIVE_POINT) {
+ return point_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_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_CURVE) {
+ return curve_attribute_float3(kg, sd, desc, dx, dy);
+ }
+#endif
+#ifdef __POINTCLOUD__
+ else if (sd->type & PRIMITIVE_POINT) {
+ return point_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_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_CURVE) {
+ return curve_attribute_float4(kg, sd, desc, dx, dy);
+ }
+#endif
+#ifdef __POINTCLOUD__
+ else if (sd->type & PRIMITIVE_POINT) {
+ return point_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)
+{
+#if defined(__HAIR__) || defined(__POINTCLOUD__)
+ if (sd->type & (PRIMITIVE_CURVE | PRIMITIVE_POINT))
+# 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;
+
+#if defined(__HAIR__) || defined(__POINTCLOUD__)
+ bool is_curve_or_point = sd->type & (PRIMITIVE_CURVE | PRIMITIVE_POINT);
+ if (is_curve_or_point) {
+ center = make_float3(0.0f, 0.0f, 0.0f);
+
+ if (sd->type & PRIMITIVE_CURVE) {
+# if defined(__HAIR__)
+ center = curve_motion_center_location(kg, sd);
+# endif
+ }
+ else if (sd->type & PRIMITIVE_POINT) {
+# if defined(__POINTCLOUD__)
+ center = point_motion_center_location(kg, sd);
+# endif
+ }
+
+ 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);
+
+#if defined(__HAIR__) || defined(__POINTCLOUD__)
+ if (is_curve_or_point) {
+ motion_pre = float4_to_float3(curve_attribute_float4(kg, sd, desc, NULL, NULL));
+ desc.offset += numkeys;
+ motion_post = float4_to_float3(curve_attribute_float4(kg, sd, desc, NULL, NULL));
+
+ /* Curve */
+ if ((sd->object_flag & SD_OBJECT_HAS_VERTEX_MOTION) == 0) {
+ object_position_transform(kg, sd, &motion_pre);
+ object_position_transform(kg, sd, &motion_post);
+ }
+ }
+ else
+#endif
+ if (sd->type & PRIMITIVE_TRIANGLE) {
+ /* Triangle */
+ if (subd_triangle_patch(kg, sd) == ~0) {
+ motion_pre = triangle_attribute_float3(kg, sd, desc, NULL, NULL);
+ desc.offset += numverts;
+ motion_post = triangle_attribute_float3(kg, sd, desc, NULL, NULL);
+ }
+ else {
+ motion_pre = subd_triangle_attribute_float3(kg, sd, desc, NULL, NULL);
+ desc.offset += numverts;
+ motion_post = subd_triangle_attribute_float3(kg, sd, desc, NULL, NULL);
+ }
+ }
+ }
+
+ /* 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/shader_data.h b/intern/cycles/kernel/geom/shader_data.h
new file mode 100644
index 00000000000..2027190fdd2
--- /dev/null
+++ b/intern/cycles/kernel/geom/shader_data.h
@@ -0,0 +1,456 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 initialize ShaderData given.
+ *
+ * Could be from an incoming ray, intersection or sampled position. */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/* ShaderData setup from incoming ray */
+
+#ifdef __OBJECT_MOTION__
+ccl_device void shader_setup_object_transforms(KernelGlobals kg,
+ ccl_private ShaderData *ccl_restrict sd,
+ float time)
+{
+ if (sd->object_flag & SD_OBJECT_MOTION) {
+ sd->ob_tfm_motion = object_fetch_transform_motion(kg, sd->object, time);
+ sd->ob_itfm_motion = transform_quick_inverse(sd->ob_tfm_motion);
+ }
+}
+#endif
+
+/* TODO: break this up if it helps reduce register pressure to load data from
+ * global memory as we write it to shader-data. */
+ccl_device_inline void shader_setup_from_ray(KernelGlobals kg,
+ ccl_private ShaderData *ccl_restrict sd,
+ ccl_private const Ray *ccl_restrict ray,
+ ccl_private const Intersection *ccl_restrict isect)
+{
+ /* Read intersection data into shader globals.
+ *
+ * TODO: this is redundant, could potentially remove some of this from
+ * ShaderData but would need to ensure that it also works for shadow
+ * shader evaluation. */
+ sd->u = isect->u;
+ sd->v = isect->v;
+ sd->ray_length = isect->t;
+ sd->type = isect->type;
+ sd->object = isect->object;
+ sd->object_flag = kernel_tex_fetch(__object_flag, sd->object);
+ sd->prim = isect->prim;
+ sd->lamp = LAMP_NONE;
+ sd->flag = 0;
+
+ /* Read matrices and time. */
+ sd->time = ray->time;
+
+#ifdef __OBJECT_MOTION__
+ shader_setup_object_transforms(kg, sd, ray->time);
+#endif
+
+ /* Read ray data into shader globals. */
+ sd->I = -ray->D;
+
+#ifdef __HAIR__
+ if (sd->type & PRIMITIVE_CURVE) {
+ /* curve */
+ curve_shader_setup(kg, sd, ray->P, ray->D, isect->t, isect->object, isect->prim);
+ }
+ else
+#endif
+#ifdef __POINTCLOUD__
+ if (sd->type & PRIMITIVE_POINT) {
+ /* point */
+ point_shader_setup(kg, sd, isect, ray);
+ }
+ else
+#endif
+ {
+ if (sd->type == PRIMITIVE_TRIANGLE) {
+ /* static triangle */
+ float3 Ng = triangle_normal(kg, sd);
+ sd->shader = kernel_tex_fetch(__tri_shader, sd->prim);
+
+ /* vectors */
+ sd->P = triangle_point_from_uv(kg, sd, isect->object, isect->prim, isect->u, isect->v);
+ sd->Ng = Ng;
+ sd->N = Ng;
+
+ /* smooth normal */
+ if (sd->shader & SHADER_SMOOTH_NORMAL)
+ sd->N = triangle_smooth_normal(kg, Ng, sd->prim, sd->u, sd->v);
+
+#ifdef __DPDU__
+ /* dPdu/dPdv */
+ triangle_dPdudv(kg, sd->prim, &sd->dPdu, &sd->dPdv);
+#endif
+ }
+ else {
+ /* motion triangle */
+ motion_triangle_shader_setup(
+ kg, sd, ray->P, ray->D, isect->t, isect->object, isect->prim, false);
+ }
+
+ if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
+ /* instance transform */
+ object_normal_transform_auto(kg, sd, &sd->N);
+ object_normal_transform_auto(kg, sd, &sd->Ng);
+#ifdef __DPDU__
+ object_dir_transform_auto(kg, sd, &sd->dPdu);
+ object_dir_transform_auto(kg, sd, &sd->dPdv);
+#endif
+ }
+ }
+
+ sd->flag = kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).flags;
+
+ /* backfacing test */
+ bool backfacing = (dot(sd->Ng, sd->I) < 0.0f);
+
+ if (backfacing) {
+ sd->flag |= SD_BACKFACING;
+ sd->Ng = -sd->Ng;
+ sd->N = -sd->N;
+#ifdef __DPDU__
+ sd->dPdu = -sd->dPdu;
+ sd->dPdv = -sd->dPdv;
+#endif
+ }
+
+#ifdef __RAY_DIFFERENTIALS__
+ /* differentials */
+ differential_transfer_compact(&sd->dP, ray->dP, ray->D, ray->dD, sd->Ng, sd->ray_length);
+ differential_incoming_compact(&sd->dI, ray->D, ray->dD);
+ differential_dudv(&sd->du, &sd->dv, sd->dPdu, sd->dPdv, sd->dP, sd->Ng);
+#endif
+}
+
+/* ShaderData setup from position sampled on mesh */
+
+ccl_device_inline void shader_setup_from_sample(KernelGlobals kg,
+ ccl_private ShaderData *ccl_restrict sd,
+ const float3 P,
+ const float3 Ng,
+ const float3 I,
+ int shader,
+ int object,
+ int prim,
+ float u,
+ float v,
+ float t,
+ float time,
+ bool object_space,
+ int lamp)
+{
+ /* vectors */
+ sd->P = P;
+ sd->N = Ng;
+ sd->Ng = Ng;
+ sd->I = I;
+ sd->shader = shader;
+ if (prim != PRIM_NONE)
+ sd->type = PRIMITIVE_TRIANGLE;
+ else if (lamp != LAMP_NONE)
+ sd->type = PRIMITIVE_LAMP;
+ else
+ sd->type = PRIMITIVE_NONE;
+
+ /* primitive */
+ sd->object = object;
+ sd->lamp = LAMP_NONE;
+ /* Currently no access to bvh prim index for strand sd->prim. */
+ sd->prim = prim;
+ sd->u = u;
+ sd->v = v;
+ sd->time = time;
+ sd->ray_length = t;
+
+ sd->flag = kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).flags;
+ sd->object_flag = 0;
+ if (sd->object != OBJECT_NONE) {
+ sd->object_flag |= kernel_tex_fetch(__object_flag, sd->object);
+
+#ifdef __OBJECT_MOTION__
+ shader_setup_object_transforms(kg, sd, time);
+#endif
+ }
+ else if (lamp != LAMP_NONE) {
+ sd->lamp = lamp;
+ }
+
+ /* transform into world space */
+ if (object_space) {
+ object_position_transform_auto(kg, sd, &sd->P);
+ object_normal_transform_auto(kg, sd, &sd->Ng);
+ sd->N = sd->Ng;
+ object_dir_transform_auto(kg, sd, &sd->I);
+ }
+
+ if (sd->type == PRIMITIVE_TRIANGLE) {
+ /* smooth normal */
+ if (sd->shader & SHADER_SMOOTH_NORMAL) {
+ sd->N = triangle_smooth_normal(kg, Ng, sd->prim, sd->u, sd->v);
+
+ if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
+ object_normal_transform_auto(kg, sd, &sd->N);
+ }
+ }
+
+ /* dPdu/dPdv */
+#ifdef __DPDU__
+ triangle_dPdudv(kg, sd->prim, &sd->dPdu, &sd->dPdv);
+
+ if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
+ object_dir_transform_auto(kg, sd, &sd->dPdu);
+ object_dir_transform_auto(kg, sd, &sd->dPdv);
+ }
+#endif
+ }
+ else {
+#ifdef __DPDU__
+ sd->dPdu = zero_float3();
+ sd->dPdv = zero_float3();
+#endif
+ }
+
+ /* backfacing test */
+ if (sd->prim != PRIM_NONE) {
+ bool backfacing = (dot(sd->Ng, sd->I) < 0.0f);
+
+ if (backfacing) {
+ sd->flag |= SD_BACKFACING;
+ sd->Ng = -sd->Ng;
+ sd->N = -sd->N;
+#ifdef __DPDU__
+ sd->dPdu = -sd->dPdu;
+ sd->dPdv = -sd->dPdv;
+#endif
+ }
+ }
+
+#ifdef __RAY_DIFFERENTIALS__
+ /* no ray differentials here yet */
+ sd->dP = differential3_zero();
+ sd->dI = differential3_zero();
+ sd->du = differential_zero();
+ sd->dv = differential_zero();
+#endif
+}
+
+/* ShaderData setup for displacement */
+
+ccl_device void shader_setup_from_displace(KernelGlobals kg,
+ ccl_private ShaderData *ccl_restrict sd,
+ int object,
+ int prim,
+ float u,
+ float v)
+{
+ float3 P, Ng, I = zero_float3();
+ int shader;
+
+ triangle_point_normal(kg, object, prim, u, v, &P, &Ng, &shader);
+
+ /* force smooth shading for displacement */
+ shader |= SHADER_SMOOTH_NORMAL;
+
+ shader_setup_from_sample(
+ kg,
+ sd,
+ P,
+ Ng,
+ I,
+ shader,
+ object,
+ prim,
+ u,
+ v,
+ 0.0f,
+ 0.5f,
+ !(kernel_tex_fetch(__object_flag, object) & SD_OBJECT_TRANSFORM_APPLIED),
+ LAMP_NONE);
+}
+
+/* ShaderData setup for point on curve. */
+
+ccl_device void shader_setup_from_curve(KernelGlobals kg,
+ ccl_private ShaderData *ccl_restrict sd,
+ int object,
+ int prim,
+ int segment,
+ float u)
+{
+ /* Primitive */
+ sd->type = PRIMITIVE_PACK_SEGMENT(PRIMITIVE_CURVE_THICK, segment);
+ sd->lamp = LAMP_NONE;
+ sd->prim = prim;
+ sd->u = u;
+ sd->v = 0.0f;
+ sd->time = 0.5f;
+ sd->ray_length = 0.0f;
+
+ /* Shader */
+ sd->shader = kernel_tex_fetch(__curves, prim).shader_id;
+ sd->flag = kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).flags;
+
+ /* Object */
+ sd->object = object;
+ sd->object_flag = kernel_tex_fetch(__object_flag, sd->object);
+#ifdef __OBJECT_MOTION__
+ shader_setup_object_transforms(kg, sd, sd->time);
+#endif
+
+ /* Get control points. */
+ KernelCurve kcurve = kernel_tex_fetch(__curves, prim);
+
+ int k0 = kcurve.first_key + PRIMITIVE_UNPACK_SEGMENT(sd->type);
+ int k1 = k0 + 1;
+ int ka = max(k0 - 1, kcurve.first_key);
+ int kb = min(k1 + 1, kcurve.first_key + kcurve.num_keys - 1);
+
+ float4 P_curve[4];
+
+ P_curve[0] = kernel_tex_fetch(__curve_keys, ka);
+ P_curve[1] = kernel_tex_fetch(__curve_keys, k0);
+ P_curve[2] = kernel_tex_fetch(__curve_keys, k1);
+ P_curve[3] = kernel_tex_fetch(__curve_keys, kb);
+
+ /* Interpolate position and tangent. */
+ sd->P = float4_to_float3(catmull_rom_basis_derivative(P_curve, sd->u));
+#ifdef __DPDU__
+ sd->dPdu = float4_to_float3(catmull_rom_basis_derivative(P_curve, sd->u));
+#endif
+
+ /* Transform into world space */
+ if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
+ object_position_transform_auto(kg, sd, &sd->P);
+#ifdef __DPDU__
+ object_dir_transform_auto(kg, sd, &sd->dPdu);
+#endif
+ }
+
+ /* No view direction, normals or bitangent. */
+ sd->I = zero_float3();
+ sd->N = zero_float3();
+ sd->Ng = zero_float3();
+#ifdef __DPDU__
+ sd->dPdv = zero_float3();
+#endif
+
+ /* No ray differentials currently. */
+#ifdef __RAY_DIFFERENTIALS__
+ sd->dP = differential3_zero();
+ sd->dI = differential3_zero();
+ sd->du = differential_zero();
+ sd->dv = differential_zero();
+#endif
+}
+
+/* ShaderData setup from ray into background */
+
+ccl_device_inline void shader_setup_from_background(KernelGlobals kg,
+ ccl_private ShaderData *ccl_restrict sd,
+ const float3 ray_P,
+ const float3 ray_D,
+ const float ray_time)
+{
+ /* for NDC coordinates */
+ sd->ray_P = ray_P;
+
+ /* vectors */
+ sd->P = ray_D;
+ sd->N = -ray_D;
+ sd->Ng = -ray_D;
+ sd->I = -ray_D;
+ sd->shader = kernel_data.background.surface_shader;
+ sd->flag = kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).flags;
+ sd->object_flag = 0;
+ sd->time = ray_time;
+ sd->ray_length = 0.0f;
+
+ sd->object = OBJECT_NONE;
+ sd->lamp = LAMP_NONE;
+ sd->prim = PRIM_NONE;
+ sd->u = 0.0f;
+ sd->v = 0.0f;
+
+#ifdef __DPDU__
+ /* dPdu/dPdv */
+ sd->dPdu = zero_float3();
+ sd->dPdv = zero_float3();
+#endif
+
+#ifdef __RAY_DIFFERENTIALS__
+ /* differentials */
+ sd->dP = differential3_zero(); /* TODO: ray->dP */
+ differential_incoming(&sd->dI, sd->dP);
+ sd->du = differential_zero();
+ sd->dv = differential_zero();
+#endif
+}
+
+/* ShaderData setup from point inside volume */
+
+#ifdef __VOLUME__
+ccl_device_inline void shader_setup_from_volume(KernelGlobals kg,
+ ccl_private ShaderData *ccl_restrict sd,
+ ccl_private const Ray *ccl_restrict ray)
+{
+
+ /* vectors */
+ sd->P = ray->P;
+ sd->N = -ray->D;
+ sd->Ng = -ray->D;
+ sd->I = -ray->D;
+ sd->shader = SHADER_NONE;
+ sd->flag = 0;
+ sd->object_flag = 0;
+ sd->time = ray->time;
+ sd->ray_length = 0.0f; /* todo: can we set this to some useful value? */
+
+ sd->object = OBJECT_NONE; /* todo: fill this for texture coordinates */
+ sd->lamp = LAMP_NONE;
+ sd->prim = PRIM_NONE;
+ sd->type = PRIMITIVE_VOLUME;
+
+ sd->u = 0.0f;
+ sd->v = 0.0f;
+
+# ifdef __DPDU__
+ /* dPdu/dPdv */
+ sd->dPdu = zero_float3();
+ sd->dPdv = zero_float3();
+# endif
+
+# ifdef __RAY_DIFFERENTIALS__
+ /* differentials */
+ sd->dP = differential3_zero(); /* TODO ray->dD */
+ differential_incoming(&sd->dI, sd->dP);
+ sd->du = differential_zero();
+ sd->dv = differential_zero();
+# endif
+
+ /* for NDC coordinates */
+ sd->ray_P = ray->P;
+ sd->ray_dP = ray->dP;
+}
+#endif /* __VOLUME__ */
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/geom/subd_triangle.h b/intern/cycles/kernel/geom/subd_triangle.h
new file mode 100644
index 00000000000..1b693a915bf
--- /dev/null
+++ b/intern/cycles/kernel/geom/subd_triangle.h
@@ -0,0 +1,680 @@
+/*
+ * 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.
+ */
+
+/* Functions for retrieving attributes on triangles produced from subdivision meshes */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/* UV coords of triangle within patch */
+
+ccl_device_inline void subd_triangle_patch_uv(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ float2 uv[3])
+{
+ uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, sd->prim);
+
+ uv[0] = kernel_tex_fetch(__tri_patch_uv, tri_vindex.x);
+ uv[1] = kernel_tex_fetch(__tri_patch_uv, tri_vindex.y);
+ uv[2] = kernel_tex_fetch(__tri_patch_uv, tri_vindex.z);
+}
+
+/* Vertex indices of patch */
+
+ccl_device_inline uint4 subd_triangle_patch_indices(KernelGlobals kg, int patch)
+{
+ uint4 indices;
+
+ indices.x = kernel_tex_fetch(__patches, patch + 0);
+ indices.y = kernel_tex_fetch(__patches, patch + 1);
+ indices.z = kernel_tex_fetch(__patches, patch + 2);
+ indices.w = kernel_tex_fetch(__patches, patch + 3);
+
+ return indices;
+}
+
+/* Originating face for patch */
+
+ccl_device_inline uint subd_triangle_patch_face(KernelGlobals kg, int patch)
+{
+ return kernel_tex_fetch(__patches, patch + 4);
+}
+
+/* Number of corners on originating face */
+
+ccl_device_inline uint subd_triangle_patch_num_corners(KernelGlobals kg, int patch)
+{
+ return kernel_tex_fetch(__patches, patch + 5) & 0xffff;
+}
+
+/* Indices of the four corners that are used by the patch */
+
+ccl_device_inline void subd_triangle_patch_corners(KernelGlobals kg, int patch, int corners[4])
+{
+ uint4 data;
+
+ data.x = kernel_tex_fetch(__patches, patch + 4);
+ data.y = kernel_tex_fetch(__patches, patch + 5);
+ data.z = kernel_tex_fetch(__patches, patch + 6);
+ data.w = kernel_tex_fetch(__patches, patch + 7);
+
+ int num_corners = data.y & 0xffff;
+
+ if (num_corners == 4) {
+ /* quad */
+ corners[0] = data.z;
+ corners[1] = data.z + 1;
+ corners[2] = data.z + 2;
+ corners[3] = data.z + 3;
+ }
+ else {
+ /* ngon */
+ int c = data.y >> 16;
+
+ corners[0] = data.z + c;
+ corners[1] = data.z + mod(c + 1, num_corners);
+ corners[2] = data.w;
+ corners[3] = data.z + mod(c - 1, num_corners);
+ }
+}
+
+/* Reading attributes on various subdivision triangle elements */
+
+ccl_device_noinline float subd_triangle_attribute_float(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ const AttributeDescriptor desc,
+ ccl_private float *dx,
+ ccl_private float *dy)
+{
+ int patch = subd_triangle_patch(kg, sd);
+
+#ifdef __PATCH_EVAL__
+ if (desc.flags & ATTR_SUBDIVIDED) {
+ float2 uv[3];
+ subd_triangle_patch_uv(kg, sd, uv);
+
+ float2 dpdu = uv[0] - uv[2];
+ float2 dpdv = uv[1] - uv[2];
+
+ /* p is [s, t] */
+ float2 p = dpdu * sd->u + dpdv * sd->v + uv[2];
+
+ float a, dads, dadt;
+ a = patch_eval_float(kg, sd, desc.offset, patch, p.x, p.y, 0, &dads, &dadt);
+
+# ifdef __RAY_DIFFERENTIALS__
+ if (dx || dy) {
+ float dsdu = dpdu.x;
+ float dtdu = dpdu.y;
+ float dsdv = dpdv.x;
+ float dtdv = dpdv.y;
+
+ if (dx) {
+ float dudx = sd->du.dx;
+ float dvdx = sd->dv.dx;
+
+ float dsdx = dsdu * dudx + dsdv * dvdx;
+ float dtdx = dtdu * dudx + dtdv * dvdx;
+
+ *dx = dads * dsdx + dadt * dtdx;
+ }
+ if (dy) {
+ float dudy = sd->du.dy;
+ float dvdy = sd->dv.dy;
+
+ float dsdy = dsdu * dudy + dsdv * dvdy;
+ float dtdy = dtdu * dudy + dtdv * dvdy;
+
+ *dy = dads * dsdy + dadt * dtdy;
+ }
+ }
+# endif
+
+ return a;
+ }
+ else
+#endif /* __PATCH_EVAL__ */
+ if (desc.element == ATTR_ELEMENT_FACE) {
+ if (dx)
+ *dx = 0.0f;
+ if (dy)
+ *dy = 0.0f;
+
+ return kernel_tex_fetch(__attributes_float, desc.offset + subd_triangle_patch_face(kg, patch));
+ }
+ else if (desc.element == ATTR_ELEMENT_VERTEX || desc.element == ATTR_ELEMENT_VERTEX_MOTION) {
+ float2 uv[3];
+ subd_triangle_patch_uv(kg, sd, uv);
+
+ uint4 v = subd_triangle_patch_indices(kg, patch);
+
+ float f0 = kernel_tex_fetch(__attributes_float, desc.offset + v.x);
+ float f1 = kernel_tex_fetch(__attributes_float, desc.offset + v.y);
+ float f2 = kernel_tex_fetch(__attributes_float, desc.offset + v.z);
+ float f3 = kernel_tex_fetch(__attributes_float, desc.offset + v.w);
+
+ if (subd_triangle_patch_num_corners(kg, patch) != 4) {
+ f1 = (f1 + f0) * 0.5f;
+ f3 = (f3 + f0) * 0.5f;
+ }
+
+ float a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y);
+ float b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y);
+ float c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y);
+
+#ifdef __RAY_DIFFERENTIALS__
+ if (dx)
+ *dx = sd->du.dx * a + sd->dv.dx * b - (sd->du.dx + sd->dv.dx) * c;
+ if (dy)
+ *dy = sd->du.dy * a + sd->dv.dy * b - (sd->du.dy + sd->dv.dy) * c;
+#endif
+
+ return sd->u * a + sd->v * b + (1.0f - sd->u - sd->v) * c;
+ }
+ else if (desc.element == ATTR_ELEMENT_CORNER) {
+ float2 uv[3];
+ subd_triangle_patch_uv(kg, sd, uv);
+
+ int corners[4];
+ subd_triangle_patch_corners(kg, patch, corners);
+
+ float f0 = kernel_tex_fetch(__attributes_float, corners[0] + desc.offset);
+ float f1 = kernel_tex_fetch(__attributes_float, corners[1] + desc.offset);
+ float f2 = kernel_tex_fetch(__attributes_float, corners[2] + desc.offset);
+ float f3 = kernel_tex_fetch(__attributes_float, corners[3] + desc.offset);
+
+ if (subd_triangle_patch_num_corners(kg, patch) != 4) {
+ f1 = (f1 + f0) * 0.5f;
+ f3 = (f3 + f0) * 0.5f;
+ }
+
+ float a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y);
+ float b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y);
+ float c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y);
+
+#ifdef __RAY_DIFFERENTIALS__
+ if (dx)
+ *dx = sd->du.dx * a + sd->dv.dx * b - (sd->du.dx + sd->dv.dx) * c;
+ if (dy)
+ *dy = sd->du.dy * a + sd->dv.dy * b - (sd->du.dy + sd->dv.dy) * c;
+#endif
+
+ return sd->u * a + sd->v * b + (1.0f - sd->u - sd->v) * c;
+ }
+ else if (desc.element == ATTR_ELEMENT_OBJECT || desc.element == ATTR_ELEMENT_MESH) {
+ if (dx)
+ *dx = 0.0f;
+ if (dy)
+ *dy = 0.0f;
+
+ return kernel_tex_fetch(__attributes_float, desc.offset);
+ }
+ else {
+ if (dx)
+ *dx = 0.0f;
+ if (dy)
+ *dy = 0.0f;
+
+ return 0.0f;
+ }
+}
+
+ccl_device_noinline float2 subd_triangle_attribute_float2(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ const AttributeDescriptor desc,
+ ccl_private float2 *dx,
+ ccl_private float2 *dy)
+{
+ int patch = subd_triangle_patch(kg, sd);
+
+#ifdef __PATCH_EVAL__
+ if (desc.flags & ATTR_SUBDIVIDED) {
+ float2 uv[3];
+ subd_triangle_patch_uv(kg, sd, uv);
+
+ float2 dpdu = uv[0] - uv[2];
+ float2 dpdv = uv[1] - uv[2];
+
+ /* p is [s, t] */
+ float2 p = dpdu * sd->u + dpdv * sd->v + uv[2];
+
+ float2 a, dads, dadt;
+
+ a = patch_eval_float2(kg, sd, desc.offset, patch, p.x, p.y, 0, &dads, &dadt);
+
+# ifdef __RAY_DIFFERENTIALS__
+ if (dx || dy) {
+ float dsdu = dpdu.x;
+ float dtdu = dpdu.y;
+ float dsdv = dpdv.x;
+ float dtdv = dpdv.y;
+
+ if (dx) {
+ float dudx = sd->du.dx;
+ float dvdx = sd->dv.dx;
+
+ float dsdx = dsdu * dudx + dsdv * dvdx;
+ float dtdx = dtdu * dudx + dtdv * dvdx;
+
+ *dx = dads * dsdx + dadt * dtdx;
+ }
+ if (dy) {
+ float dudy = sd->du.dy;
+ float dvdy = sd->dv.dy;
+
+ float dsdy = dsdu * dudy + dsdv * dvdy;
+ float dtdy = dtdu * dudy + dtdv * dvdy;
+
+ *dy = dads * dsdy + dadt * dtdy;
+ }
+ }
+# endif
+
+ return a;
+ }
+ else
+#endif /* __PATCH_EVAL__ */
+ if (desc.element == ATTR_ELEMENT_FACE) {
+ if (dx)
+ *dx = make_float2(0.0f, 0.0f);
+ if (dy)
+ *dy = make_float2(0.0f, 0.0f);
+
+ return kernel_tex_fetch(__attributes_float2,
+ desc.offset + subd_triangle_patch_face(kg, patch));
+ }
+ else if (desc.element == ATTR_ELEMENT_VERTEX || desc.element == ATTR_ELEMENT_VERTEX_MOTION) {
+ float2 uv[3];
+ subd_triangle_patch_uv(kg, sd, uv);
+
+ uint4 v = subd_triangle_patch_indices(kg, patch);
+
+ float2 f0 = kernel_tex_fetch(__attributes_float2, desc.offset + v.x);
+ float2 f1 = kernel_tex_fetch(__attributes_float2, desc.offset + v.y);
+ float2 f2 = kernel_tex_fetch(__attributes_float2, desc.offset + v.z);
+ float2 f3 = kernel_tex_fetch(__attributes_float2, desc.offset + v.w);
+
+ if (subd_triangle_patch_num_corners(kg, patch) != 4) {
+ f1 = (f1 + f0) * 0.5f;
+ f3 = (f3 + f0) * 0.5f;
+ }
+
+ float2 a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y);
+ float2 b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y);
+ float2 c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y);
+
+#ifdef __RAY_DIFFERENTIALS__
+ if (dx)
+ *dx = sd->du.dx * a + sd->dv.dx * b - (sd->du.dx + sd->dv.dx) * c;
+ if (dy)
+ *dy = sd->du.dy * a + sd->dv.dy * b - (sd->du.dy + sd->dv.dy) * c;
+#endif
+
+ return sd->u * a + sd->v * b + (1.0f - sd->u - sd->v) * c;
+ }
+ else if (desc.element == ATTR_ELEMENT_CORNER) {
+ float2 uv[3];
+ subd_triangle_patch_uv(kg, sd, uv);
+
+ int corners[4];
+ subd_triangle_patch_corners(kg, patch, corners);
+
+ float2 f0, f1, f2, f3;
+
+ f0 = kernel_tex_fetch(__attributes_float2, corners[0] + desc.offset);
+ f1 = kernel_tex_fetch(__attributes_float2, corners[1] + desc.offset);
+ f2 = kernel_tex_fetch(__attributes_float2, corners[2] + desc.offset);
+ f3 = kernel_tex_fetch(__attributes_float2, corners[3] + desc.offset);
+
+ if (subd_triangle_patch_num_corners(kg, patch) != 4) {
+ f1 = (f1 + f0) * 0.5f;
+ f3 = (f3 + f0) * 0.5f;
+ }
+
+ float2 a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y);
+ float2 b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y);
+ float2 c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y);
+
+#ifdef __RAY_DIFFERENTIALS__
+ if (dx)
+ *dx = sd->du.dx * a + sd->dv.dx * b - (sd->du.dx + sd->dv.dx) * c;
+ if (dy)
+ *dy = sd->du.dy * a + sd->dv.dy * b - (sd->du.dy + sd->dv.dy) * c;
+#endif
+
+ return sd->u * a + sd->v * b + (1.0f - sd->u - sd->v) * c;
+ }
+ else if (desc.element == ATTR_ELEMENT_OBJECT || desc.element == ATTR_ELEMENT_MESH) {
+ if (dx)
+ *dx = make_float2(0.0f, 0.0f);
+ if (dy)
+ *dy = make_float2(0.0f, 0.0f);
+
+ return kernel_tex_fetch(__attributes_float2, desc.offset);
+ }
+ 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_noinline float3 subd_triangle_attribute_float3(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ const AttributeDescriptor desc,
+ ccl_private float3 *dx,
+ ccl_private float3 *dy)
+{
+ int patch = subd_triangle_patch(kg, sd);
+
+#ifdef __PATCH_EVAL__
+ if (desc.flags & ATTR_SUBDIVIDED) {
+ float2 uv[3];
+ subd_triangle_patch_uv(kg, sd, uv);
+
+ float2 dpdu = uv[0] - uv[2];
+ float2 dpdv = uv[1] - uv[2];
+
+ /* p is [s, t] */
+ float2 p = dpdu * sd->u + dpdv * sd->v + uv[2];
+
+ float3 a, dads, dadt;
+ a = patch_eval_float3(kg, sd, desc.offset, patch, p.x, p.y, 0, &dads, &dadt);
+
+# ifdef __RAY_DIFFERENTIALS__
+ if (dx || dy) {
+ float dsdu = dpdu.x;
+ float dtdu = dpdu.y;
+ float dsdv = dpdv.x;
+ float dtdv = dpdv.y;
+
+ if (dx) {
+ float dudx = sd->du.dx;
+ float dvdx = sd->dv.dx;
+
+ float dsdx = dsdu * dudx + dsdv * dvdx;
+ float dtdx = dtdu * dudx + dtdv * dvdx;
+
+ *dx = dads * dsdx + dadt * dtdx;
+ }
+ if (dy) {
+ float dudy = sd->du.dy;
+ float dvdy = sd->dv.dy;
+
+ float dsdy = dsdu * dudy + dsdv * dvdy;
+ float dtdy = dtdu * dudy + dtdv * dvdy;
+
+ *dy = dads * dsdy + dadt * dtdy;
+ }
+ }
+# endif
+
+ return a;
+ }
+ else
+#endif /* __PATCH_EVAL__ */
+ if (desc.element == ATTR_ELEMENT_FACE) {
+ if (dx)
+ *dx = make_float3(0.0f, 0.0f, 0.0f);
+ if (dy)
+ *dy = make_float3(0.0f, 0.0f, 0.0f);
+
+ return kernel_tex_fetch(__attributes_float3,
+ desc.offset + subd_triangle_patch_face(kg, patch));
+ }
+ else if (desc.element == ATTR_ELEMENT_VERTEX || desc.element == ATTR_ELEMENT_VERTEX_MOTION) {
+ float2 uv[3];
+ subd_triangle_patch_uv(kg, sd, uv);
+
+ uint4 v = subd_triangle_patch_indices(kg, patch);
+
+ float3 f0 = kernel_tex_fetch(__attributes_float3, desc.offset + v.x);
+ float3 f1 = kernel_tex_fetch(__attributes_float3, desc.offset + v.y);
+ float3 f2 = kernel_tex_fetch(__attributes_float3, desc.offset + v.z);
+ float3 f3 = kernel_tex_fetch(__attributes_float3, desc.offset + v.w);
+
+ if (subd_triangle_patch_num_corners(kg, patch) != 4) {
+ f1 = (f1 + f0) * 0.5f;
+ f3 = (f3 + f0) * 0.5f;
+ }
+
+ float3 a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y);
+ float3 b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y);
+ float3 c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y);
+
+#ifdef __RAY_DIFFERENTIALS__
+ if (dx)
+ *dx = sd->du.dx * a + sd->dv.dx * b - (sd->du.dx + sd->dv.dx) * c;
+ if (dy)
+ *dy = sd->du.dy * a + sd->dv.dy * b - (sd->du.dy + sd->dv.dy) * c;
+#endif
+
+ return sd->u * a + sd->v * b + (1.0f - sd->u - sd->v) * c;
+ }
+ else if (desc.element == ATTR_ELEMENT_CORNER) {
+ float2 uv[3];
+ subd_triangle_patch_uv(kg, sd, uv);
+
+ int corners[4];
+ subd_triangle_patch_corners(kg, patch, corners);
+
+ float3 f0, f1, f2, f3;
+
+ f0 = kernel_tex_fetch(__attributes_float3, corners[0] + desc.offset);
+ f1 = kernel_tex_fetch(__attributes_float3, corners[1] + desc.offset);
+ f2 = kernel_tex_fetch(__attributes_float3, corners[2] + desc.offset);
+ f3 = kernel_tex_fetch(__attributes_float3, corners[3] + desc.offset);
+
+ if (subd_triangle_patch_num_corners(kg, patch) != 4) {
+ f1 = (f1 + f0) * 0.5f;
+ f3 = (f3 + f0) * 0.5f;
+ }
+
+ float3 a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y);
+ float3 b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y);
+ float3 c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y);
+
+#ifdef __RAY_DIFFERENTIALS__
+ if (dx)
+ *dx = sd->du.dx * a + sd->dv.dx * b - (sd->du.dx + sd->dv.dx) * c;
+ if (dy)
+ *dy = sd->du.dy * a + sd->dv.dy * b - (sd->du.dy + sd->dv.dy) * c;
+#endif
+
+ return sd->u * a + sd->v * b + (1.0f - sd->u - sd->v) * c;
+ }
+ else if (desc.element == ATTR_ELEMENT_OBJECT || desc.element == ATTR_ELEMENT_MESH) {
+ if (dx)
+ *dx = make_float3(0.0f, 0.0f, 0.0f);
+ if (dy)
+ *dy = make_float3(0.0f, 0.0f, 0.0f);
+
+ return kernel_tex_fetch(__attributes_float3, desc.offset);
+ }
+ 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_noinline float4 subd_triangle_attribute_float4(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ const AttributeDescriptor desc,
+ ccl_private float4 *dx,
+ ccl_private float4 *dy)
+{
+ int patch = subd_triangle_patch(kg, sd);
+
+#ifdef __PATCH_EVAL__
+ if (desc.flags & ATTR_SUBDIVIDED) {
+ float2 uv[3];
+ subd_triangle_patch_uv(kg, sd, uv);
+
+ float2 dpdu = uv[0] - uv[2];
+ float2 dpdv = uv[1] - uv[2];
+
+ /* p is [s, t] */
+ float2 p = dpdu * sd->u + dpdv * sd->v + uv[2];
+
+ float4 a, dads, dadt;
+ if (desc.type == NODE_ATTR_RGBA) {
+ a = patch_eval_uchar4(kg, sd, desc.offset, patch, p.x, p.y, 0, &dads, &dadt);
+ }
+ else {
+ a = patch_eval_float4(kg, sd, desc.offset, patch, p.x, p.y, 0, &dads, &dadt);
+ }
+
+# ifdef __RAY_DIFFERENTIALS__
+ if (dx || dy) {
+ float dsdu = dpdu.x;
+ float dtdu = dpdu.y;
+ float dsdv = dpdv.x;
+ float dtdv = dpdv.y;
+
+ if (dx) {
+ float dudx = sd->du.dx;
+ float dvdx = sd->dv.dx;
+
+ float dsdx = dsdu * dudx + dsdv * dvdx;
+ float dtdx = dtdu * dudx + dtdv * dvdx;
+
+ *dx = dads * dsdx + dadt * dtdx;
+ }
+ if (dy) {
+ float dudy = sd->du.dy;
+ float dvdy = sd->dv.dy;
+
+ float dsdy = dsdu * dudy + dsdv * dvdy;
+ float dtdy = dtdu * dudy + dtdv * dvdy;
+
+ *dy = dads * dsdy + dadt * dtdy;
+ }
+ }
+# endif
+
+ return a;
+ }
+ else
+#endif /* __PATCH_EVAL__ */
+ if (desc.element == ATTR_ELEMENT_FACE) {
+ 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 kernel_tex_fetch(__attributes_float4,
+ desc.offset + subd_triangle_patch_face(kg, patch));
+ }
+ else if (desc.element == ATTR_ELEMENT_VERTEX || desc.element == ATTR_ELEMENT_VERTEX_MOTION) {
+ float2 uv[3];
+ subd_triangle_patch_uv(kg, sd, uv);
+
+ uint4 v = subd_triangle_patch_indices(kg, patch);
+
+ float4 f0 = kernel_tex_fetch(__attributes_float4, desc.offset + v.x);
+ float4 f1 = kernel_tex_fetch(__attributes_float4, desc.offset + v.y);
+ float4 f2 = kernel_tex_fetch(__attributes_float4, desc.offset + v.z);
+ float4 f3 = kernel_tex_fetch(__attributes_float4, desc.offset + v.w);
+
+ if (subd_triangle_patch_num_corners(kg, patch) != 4) {
+ f1 = (f1 + f0) * 0.5f;
+ f3 = (f3 + f0) * 0.5f;
+ }
+
+ float4 a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y);
+ float4 b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y);
+ float4 c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y);
+
+#ifdef __RAY_DIFFERENTIALS__
+ if (dx)
+ *dx = sd->du.dx * a + sd->dv.dx * b - (sd->du.dx + sd->dv.dx) * c;
+ if (dy)
+ *dy = sd->du.dy * a + sd->dv.dy * b - (sd->du.dy + sd->dv.dy) * c;
+#endif
+
+ return sd->u * a + sd->v * b + (1.0f - sd->u - sd->v) * c;
+ }
+ else if (desc.element == ATTR_ELEMENT_CORNER || desc.element == ATTR_ELEMENT_CORNER_BYTE) {
+ float2 uv[3];
+ subd_triangle_patch_uv(kg, sd, uv);
+
+ int corners[4];
+ subd_triangle_patch_corners(kg, patch, corners);
+
+ float4 f0, f1, f2, f3;
+
+ if (desc.element == ATTR_ELEMENT_CORNER_BYTE) {
+ f0 = color_srgb_to_linear_v4(
+ color_uchar4_to_float4(kernel_tex_fetch(__attributes_uchar4, corners[0] + desc.offset)));
+ f1 = color_srgb_to_linear_v4(
+ color_uchar4_to_float4(kernel_tex_fetch(__attributes_uchar4, corners[1] + desc.offset)));
+ f2 = color_srgb_to_linear_v4(
+ color_uchar4_to_float4(kernel_tex_fetch(__attributes_uchar4, corners[2] + desc.offset)));
+ f3 = color_srgb_to_linear_v4(
+ color_uchar4_to_float4(kernel_tex_fetch(__attributes_uchar4, corners[3] + desc.offset)));
+ }
+ else {
+ f0 = kernel_tex_fetch(__attributes_float4, corners[0] + desc.offset);
+ f1 = kernel_tex_fetch(__attributes_float4, corners[1] + desc.offset);
+ f2 = kernel_tex_fetch(__attributes_float4, corners[2] + desc.offset);
+ f3 = kernel_tex_fetch(__attributes_float4, corners[3] + desc.offset);
+ }
+
+ if (subd_triangle_patch_num_corners(kg, patch) != 4) {
+ f1 = (f1 + f0) * 0.5f;
+ f3 = (f3 + f0) * 0.5f;
+ }
+
+ float4 a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y);
+ float4 b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y);
+ float4 c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y);
+
+#ifdef __RAY_DIFFERENTIALS__
+ if (dx)
+ *dx = sd->du.dx * a + sd->dv.dx * b - (sd->du.dx + sd->dv.dx) * c;
+ if (dy)
+ *dy = sd->du.dy * a + sd->dv.dy * b - (sd->du.dy + sd->dv.dy) * c;
+#endif
+
+ return sd->u * a + sd->v * b + (1.0f - sd->u - sd->v) * c;
+ }
+ else if (desc.element == ATTR_ELEMENT_OBJECT || desc.element == ATTR_ELEMENT_MESH) {
+ 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 kernel_tex_fetch(__attributes_float4, desc.offset);
+ }
+ 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);
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/geom/triangle.h b/intern/cycles/kernel/geom/triangle.h
new file mode 100644
index 00000000000..854022b3369
--- /dev/null
+++ b/intern/cycles/kernel/geom/triangle.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.
+ */
+
+/* Triangle Primitive
+ *
+ * Basic triangle with 3 vertices is used to represent mesh surfaces. For BVH
+ * ray intersection we use a precomputed triangle storage to accelerate
+ * intersection at the cost of more memory usage */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/* Normal on triangle. */
+ccl_device_inline float3 triangle_normal(KernelGlobals kg, ccl_private ShaderData *sd)
+{
+ /* load triangle vertices */
+ const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, sd->prim);
+ const float3 v0 = kernel_tex_fetch(__tri_verts, tri_vindex.w + 0);
+ const float3 v1 = kernel_tex_fetch(__tri_verts, tri_vindex.w + 1);
+ const float3 v2 = kernel_tex_fetch(__tri_verts, tri_vindex.w + 2);
+
+ /* return normal */
+ if (sd->object_flag & SD_OBJECT_NEGATIVE_SCALE_APPLIED) {
+ return normalize(cross(v2 - v0, v1 - v0));
+ }
+ else {
+ return normalize(cross(v1 - v0, v2 - v0));
+ }
+}
+
+/* Point and normal on triangle. */
+ccl_device_inline void triangle_point_normal(KernelGlobals kg,
+ int object,
+ int prim,
+ float u,
+ float v,
+ ccl_private float3 *P,
+ ccl_private float3 *Ng,
+ ccl_private int *shader)
+{
+ /* load triangle vertices */
+ const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
+ float3 v0 = kernel_tex_fetch(__tri_verts, tri_vindex.w + 0);
+ float3 v1 = kernel_tex_fetch(__tri_verts, tri_vindex.w + 1);
+ float3 v2 = kernel_tex_fetch(__tri_verts, tri_vindex.w + 2);
+ /* compute point */
+ float t = 1.0f - u - v;
+ *P = (u * v0 + v * v1 + t * v2);
+ /* get object flags */
+ int object_flag = kernel_tex_fetch(__object_flag, object);
+ /* compute normal */
+ if (object_flag & SD_OBJECT_NEGATIVE_SCALE_APPLIED) {
+ *Ng = normalize(cross(v2 - v0, v1 - v0));
+ }
+ else {
+ *Ng = normalize(cross(v1 - v0, v2 - v0));
+ }
+ /* shader`*/
+ *shader = kernel_tex_fetch(__tri_shader, prim);
+}
+
+/* Triangle vertex locations */
+
+ccl_device_inline void triangle_vertices(KernelGlobals kg, int prim, float3 P[3])
+{
+ const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
+ P[0] = kernel_tex_fetch(__tri_verts, tri_vindex.w + 0);
+ P[1] = kernel_tex_fetch(__tri_verts, tri_vindex.w + 1);
+ P[2] = kernel_tex_fetch(__tri_verts, tri_vindex.w + 2);
+}
+
+/* Triangle vertex locations and vertex normals */
+
+ccl_device_inline void triangle_vertices_and_normals(KernelGlobals kg,
+ int prim,
+ float3 P[3],
+ float3 N[3])
+{
+ const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
+ P[0] = kernel_tex_fetch(__tri_verts, tri_vindex.w + 0);
+ P[1] = kernel_tex_fetch(__tri_verts, tri_vindex.w + 1);
+ P[2] = kernel_tex_fetch(__tri_verts, tri_vindex.w + 2);
+ N[0] = kernel_tex_fetch(__tri_vnormal, tri_vindex.x);
+ N[1] = kernel_tex_fetch(__tri_vnormal, tri_vindex.y);
+ N[2] = kernel_tex_fetch(__tri_vnormal, tri_vindex.z);
+}
+
+/* Interpolate smooth vertex normal from vertices */
+
+ccl_device_inline float3
+triangle_smooth_normal(KernelGlobals kg, float3 Ng, int prim, float u, float v)
+{
+ /* load triangle vertices */
+ const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
+ float3 n0 = kernel_tex_fetch(__tri_vnormal, tri_vindex.x);
+ float3 n1 = kernel_tex_fetch(__tri_vnormal, tri_vindex.y);
+ float3 n2 = kernel_tex_fetch(__tri_vnormal, tri_vindex.z);
+
+ float3 N = safe_normalize((1.0f - u - v) * n2 + u * n0 + v * n1);
+
+ return is_zero(N) ? Ng : N;
+}
+
+ccl_device_inline float3 triangle_smooth_normal_unnormalized(
+ KernelGlobals kg, ccl_private const ShaderData *sd, float3 Ng, int prim, float u, float v)
+{
+ /* load triangle vertices */
+ const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
+ float3 n0 = kernel_tex_fetch(__tri_vnormal, tri_vindex.x);
+ float3 n1 = kernel_tex_fetch(__tri_vnormal, tri_vindex.y);
+ float3 n2 = kernel_tex_fetch(__tri_vnormal, tri_vindex.z);
+
+ /* ensure that the normals are in object space */
+ if (sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED) {
+ object_inverse_normal_transform(kg, sd, &n0);
+ object_inverse_normal_transform(kg, sd, &n1);
+ object_inverse_normal_transform(kg, sd, &n2);
+ }
+
+ float3 N = (1.0f - u - v) * n2 + u * n0 + v * n1;
+
+ return is_zero(N) ? Ng : N;
+}
+
+/* Ray differentials on triangle */
+
+ccl_device_inline void triangle_dPdudv(KernelGlobals kg,
+ int prim,
+ ccl_private float3 *dPdu,
+ ccl_private float3 *dPdv)
+{
+ /* fetch triangle vertex coordinates */
+ const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
+ const float3 p0 = kernel_tex_fetch(__tri_verts, tri_vindex.w + 0);
+ const float3 p1 = kernel_tex_fetch(__tri_verts, tri_vindex.w + 1);
+ const float3 p2 = kernel_tex_fetch(__tri_verts, tri_vindex.w + 2);
+
+ /* compute derivatives of P w.r.t. uv */
+ *dPdu = (p0 - p2);
+ *dPdv = (p1 - p2);
+}
+
+/* Reading attributes on various triangle elements */
+
+ccl_device float triangle_attribute_float(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ const AttributeDescriptor desc,
+ ccl_private float *dx,
+ ccl_private float *dy)
+{
+ if (desc.element & (ATTR_ELEMENT_VERTEX | ATTR_ELEMENT_VERTEX_MOTION | ATTR_ELEMENT_CORNER)) {
+ float f0, f1, f2;
+
+ if (desc.element & (ATTR_ELEMENT_VERTEX | ATTR_ELEMENT_VERTEX_MOTION)) {
+ const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, sd->prim);
+ f0 = kernel_tex_fetch(__attributes_float, desc.offset + tri_vindex.x);
+ f1 = kernel_tex_fetch(__attributes_float, desc.offset + tri_vindex.y);
+ f2 = kernel_tex_fetch(__attributes_float, desc.offset + tri_vindex.z);
+ }
+ else {
+ const int tri = desc.offset + sd->prim * 3;
+ f0 = kernel_tex_fetch(__attributes_float, tri + 0);
+ f1 = kernel_tex_fetch(__attributes_float, tri + 1);
+ f2 = kernel_tex_fetch(__attributes_float, tri + 2);
+ }
+
+#ifdef __RAY_DIFFERENTIALS__
+ if (dx)
+ *dx = sd->du.dx * f0 + sd->dv.dx * f1 - (sd->du.dx + sd->dv.dx) * f2;
+ if (dy)
+ *dy = sd->du.dy * f0 + sd->dv.dy * f1 - (sd->du.dy + sd->dv.dy) * f2;
+#endif
+
+ return sd->u * f0 + sd->v * f1 + (1.0f - sd->u - sd->v) * f2;
+ }
+ else {
+#ifdef __RAY_DIFFERENTIALS__
+ if (dx)
+ *dx = 0.0f;
+ if (dy)
+ *dy = 0.0f;
+#endif
+
+ if (desc.element & (ATTR_ELEMENT_FACE | ATTR_ELEMENT_OBJECT | ATTR_ELEMENT_MESH)) {
+ const int offset = (desc.element == ATTR_ELEMENT_FACE) ? desc.offset + sd->prim :
+ desc.offset;
+ return kernel_tex_fetch(__attributes_float, offset);
+ }
+ else {
+ return 0.0f;
+ }
+ }
+}
+
+ccl_device float2 triangle_attribute_float2(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ const AttributeDescriptor desc,
+ ccl_private float2 *dx,
+ ccl_private float2 *dy)
+{
+ if (desc.element & (ATTR_ELEMENT_VERTEX | ATTR_ELEMENT_VERTEX_MOTION | ATTR_ELEMENT_CORNER)) {
+ float2 f0, f1, f2;
+
+ if (desc.element & (ATTR_ELEMENT_VERTEX | ATTR_ELEMENT_VERTEX_MOTION)) {
+ const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, sd->prim);
+ f0 = kernel_tex_fetch(__attributes_float2, desc.offset + tri_vindex.x);
+ f1 = kernel_tex_fetch(__attributes_float2, desc.offset + tri_vindex.y);
+ f2 = kernel_tex_fetch(__attributes_float2, desc.offset + tri_vindex.z);
+ }
+ else {
+ const int tri = desc.offset + sd->prim * 3;
+ f0 = kernel_tex_fetch(__attributes_float2, tri + 0);
+ f1 = kernel_tex_fetch(__attributes_float2, tri + 1);
+ f2 = kernel_tex_fetch(__attributes_float2, tri + 2);
+ }
+
+#ifdef __RAY_DIFFERENTIALS__
+ if (dx)
+ *dx = sd->du.dx * f0 + sd->dv.dx * f1 - (sd->du.dx + sd->dv.dx) * f2;
+ if (dy)
+ *dy = sd->du.dy * f0 + sd->dv.dy * f1 - (sd->du.dy + sd->dv.dy) * f2;
+#endif
+
+ return sd->u * f0 + sd->v * f1 + (1.0f - sd->u - sd->v) * f2;
+ }
+ else {
+#ifdef __RAY_DIFFERENTIALS__
+ if (dx)
+ *dx = make_float2(0.0f, 0.0f);
+ if (dy)
+ *dy = make_float2(0.0f, 0.0f);
+#endif
+
+ if (desc.element & (ATTR_ELEMENT_FACE | ATTR_ELEMENT_OBJECT | ATTR_ELEMENT_MESH)) {
+ const int offset = (desc.element == ATTR_ELEMENT_FACE) ? desc.offset + sd->prim :
+ desc.offset;
+ return kernel_tex_fetch(__attributes_float2, offset);
+ }
+ else {
+ return make_float2(0.0f, 0.0f);
+ }
+ }
+}
+
+ccl_device float3 triangle_attribute_float3(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ const AttributeDescriptor desc,
+ ccl_private float3 *dx,
+ ccl_private float3 *dy)
+{
+ if (desc.element & (ATTR_ELEMENT_VERTEX | ATTR_ELEMENT_VERTEX_MOTION | ATTR_ELEMENT_CORNER)) {
+ float3 f0, f1, f2;
+
+ if (desc.element & (ATTR_ELEMENT_VERTEX | ATTR_ELEMENT_VERTEX_MOTION)) {
+ const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, sd->prim);
+ f0 = kernel_tex_fetch(__attributes_float3, desc.offset + tri_vindex.x);
+ f1 = kernel_tex_fetch(__attributes_float3, desc.offset + tri_vindex.y);
+ f2 = kernel_tex_fetch(__attributes_float3, desc.offset + tri_vindex.z);
+ }
+ else {
+ const int tri = desc.offset + sd->prim * 3;
+ f0 = kernel_tex_fetch(__attributes_float3, tri + 0);
+ f1 = kernel_tex_fetch(__attributes_float3, tri + 1);
+ f2 = kernel_tex_fetch(__attributes_float3, tri + 2);
+ }
+
+#ifdef __RAY_DIFFERENTIALS__
+ if (dx)
+ *dx = sd->du.dx * f0 + sd->dv.dx * f1 - (sd->du.dx + sd->dv.dx) * f2;
+ if (dy)
+ *dy = sd->du.dy * f0 + sd->dv.dy * f1 - (sd->du.dy + sd->dv.dy) * f2;
+#endif
+
+ return sd->u * f0 + sd->v * f1 + (1.0f - sd->u - sd->v) * f2;
+ }
+ else {
+#ifdef __RAY_DIFFERENTIALS__
+ if (dx)
+ *dx = make_float3(0.0f, 0.0f, 0.0f);
+ if (dy)
+ *dy = make_float3(0.0f, 0.0f, 0.0f);
+#endif
+
+ if (desc.element & (ATTR_ELEMENT_FACE | ATTR_ELEMENT_OBJECT | ATTR_ELEMENT_MESH)) {
+ const int offset = (desc.element == ATTR_ELEMENT_FACE) ? desc.offset + sd->prim :
+ desc.offset;
+ return kernel_tex_fetch(__attributes_float3, offset);
+ }
+ else {
+ return make_float3(0.0f, 0.0f, 0.0f);
+ }
+ }
+}
+
+ccl_device float4 triangle_attribute_float4(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ const AttributeDescriptor desc,
+ ccl_private float4 *dx,
+ ccl_private float4 *dy)
+{
+ if (desc.element & (ATTR_ELEMENT_VERTEX | ATTR_ELEMENT_VERTEX_MOTION | ATTR_ELEMENT_CORNER |
+ ATTR_ELEMENT_CORNER_BYTE)) {
+ float4 f0, f1, f2;
+
+ if (desc.element & (ATTR_ELEMENT_VERTEX | ATTR_ELEMENT_VERTEX_MOTION)) {
+ const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, sd->prim);
+ f0 = kernel_tex_fetch(__attributes_float4, desc.offset + tri_vindex.x);
+ f1 = kernel_tex_fetch(__attributes_float4, desc.offset + tri_vindex.y);
+ f2 = kernel_tex_fetch(__attributes_float4, desc.offset + tri_vindex.z);
+ }
+ else {
+ const int tri = desc.offset + sd->prim * 3;
+ if (desc.element == ATTR_ELEMENT_CORNER) {
+ f0 = kernel_tex_fetch(__attributes_float4, tri + 0);
+ f1 = kernel_tex_fetch(__attributes_float4, tri + 1);
+ f2 = kernel_tex_fetch(__attributes_float4, tri + 2);
+ }
+ else {
+ f0 = color_srgb_to_linear_v4(
+ color_uchar4_to_float4(kernel_tex_fetch(__attributes_uchar4, tri + 0)));
+ f1 = color_srgb_to_linear_v4(
+ color_uchar4_to_float4(kernel_tex_fetch(__attributes_uchar4, tri + 1)));
+ f2 = color_srgb_to_linear_v4(
+ color_uchar4_to_float4(kernel_tex_fetch(__attributes_uchar4, tri + 2)));
+ }
+ }
+
+#ifdef __RAY_DIFFERENTIALS__
+ if (dx)
+ *dx = sd->du.dx * f0 + sd->dv.dx * f1 - (sd->du.dx + sd->dv.dx) * f2;
+ if (dy)
+ *dy = sd->du.dy * f0 + sd->dv.dy * f1 - (sd->du.dy + sd->dv.dy) * f2;
+#endif
+
+ return sd->u * f0 + sd->v * f1 + (1.0f - sd->u - sd->v) * f2;
+ }
+ else {
+#ifdef __RAY_DIFFERENTIALS__
+ 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);
+#endif
+
+ if (desc.element & (ATTR_ELEMENT_FACE | ATTR_ELEMENT_OBJECT | ATTR_ELEMENT_MESH)) {
+ const int offset = (desc.element == ATTR_ELEMENT_FACE) ? desc.offset + sd->prim :
+ desc.offset;
+ return kernel_tex_fetch(__attributes_float4, offset);
+ }
+ else {
+ return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ }
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/geom/triangle_intersect.h b/intern/cycles/kernel/geom/triangle_intersect.h
new file mode 100644
index 00000000000..8458cf020a0
--- /dev/null
+++ b/intern/cycles/kernel/geom/triangle_intersect.h
@@ -0,0 +1,171 @@
+/*
+ * 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,
+ int prim_addr)
+{
+ const uint tri_vindex = kernel_tex_fetch(__tri_vindex, prim).w;
+ const float3 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);
+ float t, u, v;
+ if (ray_triangle_intersect(P, dir, tmax, tri_a, tri_b, tri_c, &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;
+ 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 prim,
+ int prim_addr,
+ float tmax,
+ ccl_private uint *lcg_state,
+ int max_hits)
+{
+ const uint tri_vindex = kernel_tex_fetch(__tri_vindex, prim).w;
+ const float3 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);
+ float t, u, v;
+ if (!ray_triangle_intersect(P, dir, tmax, tri_a, tri_b, tri_c, &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 = object;
+ isect->type = PRIMITIVE_TRIANGLE;
+ isect->u = u;
+ isect->v = v;
+ isect->t = t;
+
+ /* Record geometric normal. */
+ local_isect->Ng[hit] = normalize(cross(tri_b - tri_a, tri_c - tri_a));
+
+ return false;
+}
+#endif /* __BVH_LOCAL__ */
+
+/**
+ * Use the barycentric coordinates to get the intersection location
+ */
+ccl_device_inline float3 triangle_point_from_uv(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ const int isect_object,
+ const int isect_prim,
+ const float u,
+ const float v)
+{
+ const uint tri_vindex = kernel_tex_fetch(__tri_vindex, isect_prim).w;
+ const packed_float3 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);
+ float w = 1.0f - u - v;
+
+ float3 P = u * tri_a + v * tri_b + w * tri_c;
+
+ if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
+ const Transform tfm = object_get_transform(kg, sd);
+ P = transform_point(&tfm, P);
+ }
+
+ return P;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/geom/volume.h b/intern/cycles/kernel/geom/volume.h
new file mode 100644
index 00000000000..387eb2646da
--- /dev/null
+++ b/intern/cycles/kernel/geom/volume.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* Volume Primitive
+ *
+ * Volumes are just regions inside meshes with the mesh surface as boundaries.
+ * There isn't as much data to access as for surfaces, there is only a position
+ * to do lookups in 3D voxel or procedural textures.
+ *
+ * 3D voxel textures can be assigned as attributes per mesh, which means the
+ * same shader can be used for volume objects with different densities, etc. */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+#ifdef __VOLUME__
+
+/* Return position normalized to 0..1 in mesh bounds */
+
+ccl_device_inline float3 volume_normalized_position(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ float3 P)
+{
+ /* todo: optimize this so it's just a single matrix multiplication when
+ * possible (not motion blur), or perhaps even just translation + scale */
+ const AttributeDescriptor desc = find_attribute(kg, sd, ATTR_STD_GENERATED_TRANSFORM);
+
+ object_inverse_position_transform(kg, sd, &P);
+
+ if (desc.offset != ATTR_STD_NOT_FOUND) {
+ Transform tfm = primitive_attribute_matrix(kg, sd, desc);
+ P = transform_point(&tfm, P);
+ }
+
+ return P;
+}
+
+ccl_device float volume_attribute_value_to_float(const float4 value)
+{
+ return average(float4_to_float3(value));
+}
+
+ccl_device float volume_attribute_value_to_alpha(const float4 value)
+{
+ return value.w;
+}
+
+ccl_device float3 volume_attribute_value_to_float3(const float4 value)
+{
+ if (value.w > 1e-6f && value.w != 1.0f) {
+ /* For RGBA colors, unpremultiply after interpolation. */
+ return float4_to_float3(value) / value.w;
+ }
+ else {
+ return float4_to_float3(value);
+ }
+}
+
+ccl_device float4 volume_attribute_float4(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ const AttributeDescriptor desc)
+{
+ if (desc.element & (ATTR_ELEMENT_OBJECT | ATTR_ELEMENT_MESH)) {
+ return kernel_tex_fetch(__attributes_float4, desc.offset);
+ }
+ else if (desc.element == ATTR_ELEMENT_VOXEL) {
+ /* todo: optimize this so we don't have to transform both here and in
+ * kernel_tex_image_interp_3d when possible. Also could optimize for the
+ * common case where transform is translation/scale only. */
+ float3 P = sd->P;
+ object_inverse_position_transform(kg, sd, &P);
+ InterpolationType interp = (sd->flag & SD_VOLUME_CUBIC) ? INTERPOLATION_CUBIC :
+ INTERPOLATION_NONE;
+ return kernel_tex_image_interp_3d(kg, desc.offset, P, interp);
+ }
+ else {
+ return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ }
+}
+
+#endif
+
+CCL_NAMESPACE_END
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..f4a2fbea405
--- /dev/null
+++ b/intern/cycles/kernel/integrator/init_from_bake.h
@@ -0,0 +1,205 @@
+/*
+ * 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, tile->sample_offset);
+
+ /* Setup render buffers. */
+ const int index = INTEGRATOR_STATE(state, path, render_pixel_index);
+ const int pass_stride = kernel_data.film.pass_stride;
+ ccl_global float *buffer = render_buffer + index * pass_stride;
+
+ ccl_global float *primitive = buffer + kernel_data.film.pass_bake_primitive;
+ ccl_global float *differential = 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) {
+ /* Accumulate transparency for empty pixels. */
+ kernel_accum_transparent(kg, state, 0, 1.0f, buffer);
+ 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..59dd1a9fa75
--- /dev/null
+++ b/intern/cycles/kernel/integrator/init_from_camera.h
@@ -0,0 +1,125 @@
+/*
+ * 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, tile->sample_offset);
+
+ /* 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 96db606cee1..00000000000
--- a/intern/cycles/kernel/integrator/integrator_init_from_bake.h
+++ /dev/null
@@ -1,182 +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(INTEGRATOR_STATE_ARGS,
- const ccl_global 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(INTEGRATOR_STATE_PASS, tile, x, y);
-
- /* Check whether the pixel has converged and should not be sampled anymore. */
- if (!kernel_need_sample_pixel(INTEGRATOR_STATE_PASS, render_buffer)) {
- return false;
- }
-
- /* Always count the sample, even if the camera sample will reject the ray. */
- const int sample = kernel_accum_sample(INTEGRATOR_STATE_PASS, render_buffer, scheduled_sample);
-
- /* Setup render buffers. */
- const int index = INTEGRATOR_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(INTEGRATOR_STATE_PASS, 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. */
- float3 P, Ng;
- int shader;
- triangle_point_normal(kg, kernel_data.bake.object_index, prim, u, v, &P, &Ng, &shader);
- 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(INTEGRATOR_STATE_PASS, &ray);
-
- /* Setup next kernel to execute. */
- INTEGRATOR_PATH_INIT(DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND);
- }
- else {
- /* Surface baking. */
- const float3 N = (shader & SHADER_SMOOTH_NORMAL) ? triangle_smooth_normal(kg, Ng, prim, u, v) :
- 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);
- 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(INTEGRATOR_STATE_PASS, &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;
-#ifdef __EMBREE__
- isect.Ng = Ng;
-#endif
- integrator_state_write_isect(INTEGRATOR_STATE_PASS, &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) || (kernel_data.film.pass_ao != PASS_UNUSED)) {
- 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 58e7bde4c94..00000000000
--- a/intern/cycles/kernel/integrator/integrator_init_from_camera.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/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(const KernelGlobals *ccl_restrict kg,
- const int sample,
- const int x,
- const int y,
- const uint rng_hash,
- 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(INTEGRATOR_STATE_ARGS,
- const ccl_global 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(INTEGRATOR_STATE_PASS, tile, x, y);
-
- /* Check whether the pixel has converged and should not be sampled anymore. */
- if (!kernel_need_sample_pixel(INTEGRATOR_STATE_PASS, 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(INTEGRATOR_STATE_PASS, 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(INTEGRATOR_STATE_PASS, &ray);
- }
-
- /* Initialize path state for path integration. */
- path_state_init_integrator(INTEGRATOR_STATE_PASS, 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 34ca6814534..00000000000
--- a/intern/cycles/kernel/integrator/integrator_intersect_closest.h
+++ /dev/null
@@ -1,248 +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(INTEGRATOR_STATE_ARGS,
- 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(INTEGRATOR_STATE_PASS)) {
- if (shader_flags & (SD_HAS_TRANSPARENT_SHADOW | SD_HAS_EMISSION)) {
- INTEGRATOR_STATE_WRITE(path, flag) |= PATH_RAY_TERMINATE_AFTER_TRANSPARENT;
- }
- else if (!integrator_state_volume_stack_is_empty(INTEGRATOR_STATE_PASS)) {
- INTEGRATOR_STATE_WRITE(path, flag) |= PATH_RAY_TERMINATE_AFTER_VOLUME;
- }
- else {
- return true;
- }
- }
-
- /* Load random number state. */
- RNGState rng_state;
- path_state_rng_load(INTEGRATOR_STATE_PASS, &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 int path_flag = INTEGRATOR_STATE(path, flag);
- const float probability = path_state_continuation_probability(INTEGRATOR_STATE_PASS, 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(path, flag) |= PATH_RAY_TERMINATE_ON_NEXT_SURFACE;
- }
- else if (!integrator_state_volume_stack_is_empty(INTEGRATOR_STATE_PASS)) {
- /* TODO: only do this for emissive volumes. */
- INTEGRATOR_STATE_WRITE(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(
- INTEGRATOR_STATE_ARGS,
- 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) ||
- (kernel_data.film.pass_ao != PASS_UNUSED));
-
- 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(INTEGRATOR_STATE_PASS, object_flags)) {
- if (kernel_data.film.use_approximate_shadow_catcher && !kernel_data.background.transparent) {
- INTEGRATOR_STATE_WRITE(path, flag) |= PATH_RAY_SHADOW_CATCHER_BACKGROUND;
-
- if (use_raytrace_kernel) {
- INTEGRATOR_PATH_INIT(DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND);
- }
- else {
- 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(INTEGRATOR_STATE_ARGS)
-{
- PROFILING_INIT(kg, PROFILING_INTERSECT_CLOSEST);
-
- /* Read ray from integrator state into local memory. */
- Ray ray ccl_optional_struct_init;
- integrator_state_read_ray(INTEGRATOR_STATE_PASS, &ray);
- kernel_assert(ray.t != 0.0f);
-
- const uint visibility = path_state_ray_visibility(INTEGRATOR_STATE_PASS);
- const int last_isect_prim = INTEGRATOR_STATE(isect, prim);
- const int last_isect_object = INTEGRATOR_STATE(isect, object);
-
- /* Trick to use short AO rays to approximate indirect light at the end of the path. */
- if (path_state_ao_bounce(INTEGRATOR_STATE_PASS)) {
- ray.t = kernel_data.integrator.ao_bounces_distance;
-
- const int last_object = last_isect_object != OBJECT_NONE ?
- last_isect_object :
- kernel_tex_fetch(__prim_object, last_isect_prim);
- const float object_ao_distance = kernel_tex_fetch(__objects, last_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(isect, type);
- const int path_flag = INTEGRATOR_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(INTEGRATOR_STATE_PASS, &isect);
-
-#ifdef __VOLUME__
- if (!integrator_state_volume_stack_is_empty(INTEGRATOR_STATE_PASS)) {
- 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>(
- INTEGRATOR_STATE_PASS, 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>(
- INTEGRATOR_STATE_PASS, flags)) {
- integrator_intersect_shader_next_kernel<DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST>(
- INTEGRATOR_STATE_PASS, &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/integrator_intersect_shadow.h
deleted file mode 100644
index 5bd9cfda4a4..00000000000
--- a/intern/cycles/kernel/integrator/integrator_intersect_shadow.h
+++ /dev/null
@@ -1,144 +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
-
-CCL_NAMESPACE_BEGIN
-
-/* Visibility for the shadow ray. */
-ccl_device_forceinline uint integrate_intersect_shadow_visibility(INTEGRATOR_STATE_CONST_ARGS)
-{
- uint visibility = PATH_RAY_SHADOW;
-
-#ifdef __SHADOW_CATCHER__
- const uint32_t path_flag = INTEGRATOR_STATE(shadow_path, flag);
- visibility = SHADOW_CATCHER_PATH_VISIBILITY(path_flag, visibility);
-#endif
-
- return visibility;
-}
-
-ccl_device bool integrate_intersect_shadow_opaque(INTEGRATOR_STATE_ARGS,
- const Ray *ray,
- const uint visibility)
-{
- /* Mask which will pick only opaque visibility bits from the `visibility`.
- * Calculate the mask at compile time: the visibility will either be a high bits for the shadow
- * catcher objects, or lower bits for the regular objects (there is no need to check the path
- * state here again). */
- constexpr const uint opaque_mask = SHADOW_CATCHER_VISIBILITY_SHIFT(PATH_RAY_SHADOW_OPAQUE) |
- PATH_RAY_SHADOW_OPAQUE;
-
- Intersection isect;
- const bool opaque_hit = scene_intersect(kg, ray, visibility & opaque_mask, &isect);
-
- if (!opaque_hit) {
- INTEGRATOR_STATE_WRITE(shadow_path, num_hits) = 0;
- }
-
- return opaque_hit;
-}
-
-ccl_device_forceinline int integrate_shadow_max_transparent_hits(INTEGRATOR_STATE_CONST_ARGS)
-{
- const int transparent_max_bounce = kernel_data.integrator.transparent_max_bounce;
- const int transparent_bounce = INTEGRATOR_STATE(shadow_path, transparent_bounce);
-
- return max(transparent_max_bounce - transparent_bounce - 1, 0);
-}
-
-#ifdef __TRANSPARENT_SHADOWS__
-ccl_device bool integrate_intersect_shadow_transparent(INTEGRATOR_STATE_ARGS,
- const Ray *ray,
- const uint visibility)
-{
- Intersection isect[INTEGRATOR_SHADOW_ISECT_SIZE];
-
- /* Limit the number hits to the max transparent bounces allowed and the size that we
- * have available in the integrator state. */
- const uint max_transparent_hits = integrate_shadow_max_transparent_hits(INTEGRATOR_STATE_PASS);
- const uint max_hits = min(max_transparent_hits, (uint)INTEGRATOR_SHADOW_ISECT_SIZE);
- uint num_hits = 0;
- bool opaque_hit = scene_intersect_shadow_all(kg, ray, isect, visibility, max_hits, &num_hits);
-
- /* If number of hits exceed the transparent bounces limit, make opaque. */
- if (num_hits > max_transparent_hits) {
- opaque_hit = true;
- }
-
- if (!opaque_hit) {
- uint num_recorded_hits = min(num_hits, max_hits);
-
- if (num_recorded_hits > 0) {
- sort_intersections(isect, num_recorded_hits);
-
- /* Write intersection result into global integrator state memory. */
- for (int hit = 0; hit < num_recorded_hits; hit++) {
- integrator_state_write_shadow_isect(INTEGRATOR_STATE_PASS, &isect[hit], hit);
- }
- }
-
- INTEGRATOR_STATE_WRITE(shadow_path, num_hits) = num_hits;
- }
- else {
- INTEGRATOR_STATE_WRITE(shadow_path, num_hits) = 0;
- }
-
- return opaque_hit;
-}
-#endif
-
-ccl_device void integrator_intersect_shadow(INTEGRATOR_STATE_ARGS)
-{
- PROFILING_INIT(kg, PROFILING_INTERSECT_SHADOW);
-
- /* Read ray from integrator state into local memory. */
- Ray ray ccl_optional_struct_init;
- integrator_state_read_shadow_ray(INTEGRATOR_STATE_PASS, &ray);
-
- /* Compute visibility. */
- const uint visibility = integrate_intersect_shadow_visibility(INTEGRATOR_STATE_PASS);
-
-#ifdef __TRANSPARENT_SHADOWS__
- /* TODO: compile different kernels depending on this? Especially for OptiX
- * conditional trace calls are bad. */
- const bool opaque_hit =
- (kernel_data.integrator.transparent_shadows) ?
- integrate_intersect_shadow_transparent(INTEGRATOR_STATE_PASS, &ray, visibility) :
- integrate_intersect_shadow_opaque(INTEGRATOR_STATE_PASS, &ray, visibility);
-#else
- const bool opaque_hit = integrate_intersect_shadow_opaque(
- INTEGRATOR_STATE_PASS, &ray, visibility);
-#endif
-
- if (opaque_hit) {
- /* Hit an opaque surface, shadow path ends here. */
- INTEGRATOR_SHADOW_PATH_TERMINATE(DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW);
- return;
- }
- else {
- /* Hit nothing or transparent surfaces, continue to shadow kernel
- * for shading and render buffer output.
- *
- * TODO: could also write to render buffer directly if no transparent shadows?
- * Could save a kernel execution for the common case. */
- INTEGRATOR_SHADOW_PATH_NEXT(DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW,
- DEVICE_KERNEL_INTEGRATOR_SHADE_SHADOW);
- 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 7c090952dc7..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(INTEGRATOR_STATE_ARGS)
-{
- PROFILING_INIT(kg, PROFILING_INTERSECT_SUBSURFACE);
-
-#ifdef __SUBSURFACE__
- if (subsurface_scatter(INTEGRATOR_STATE_PASS)) {
- 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 60d8a8e3e54..00000000000
--- a/intern/cycles/kernel/integrator/integrator_intersect_volume_stack.h
+++ /dev/null
@@ -1,198 +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(INTEGRATOR_STATE_ARGS,
- const float3 from_P,
- const float3 to_P)
-{
- PROFILING_INIT(kg, PROFILING_INTERSECT_VOLUME_STACK);
-
- ShaderDataTinyStorage stack_sd_storage;
- 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);
-
-#ifdef __VOLUME_RECORD_ALL__
- Intersection hits[2 * 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(INTEGRATOR_STATE_PASS, 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(INTEGRATOR_STATE_PASS, 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(INTEGRATOR_STATE_ARGS)
-{
- PROFILING_INIT(kg, PROFILING_INTERSECT_VOLUME_STACK);
-
- ShaderDataTinyStorage stack_sd_storage;
- ShaderData *stack_sd = AS_SHADER_DATA(&stack_sd_storage);
-
- Ray volume_ray ccl_optional_struct_init;
- integrator_state_read_ray(INTEGRATOR_STATE_PASS, &volume_ray);
- volume_ray.t = FLT_MAX;
-
- const uint visibility = (INTEGRATOR_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(INTEGRATOR_STATE_PASS, stack_index, new_entry);
- stack_index++;
- }
-
-#ifdef __VOLUME_RECORD_ALL__
- Intersection hits[2 * 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[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(INTEGRATOR_STATE_PASS, 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(INTEGRATOR_STATE_PASS, 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
- int enclosed_volumes[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(INTEGRATOR_STATE_PASS, 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(INTEGRATOR_STATE_PASS, 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(INTEGRATOR_STATE_PASS, 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 91363ea1c7f..00000000000
--- a/intern/cycles/kernel/integrator/integrator_megakernel.h
+++ /dev/null
@@ -1,93 +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(INTEGRATOR_STATE_ARGS,
- 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.
- *
- * TODO: investigate if we can use device side enqueue for GPUs to avoid
- * having to compile this big kernel. */
- while (true) {
- if (INTEGRATOR_STATE(shadow_path, queued_kernel)) {
- /* First handle any shadow paths before we potentially create more shadow paths. */
- switch (INTEGRATOR_STATE(shadow_path, queued_kernel)) {
- case DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW:
- integrator_intersect_shadow(INTEGRATOR_STATE_PASS);
- break;
- case DEVICE_KERNEL_INTEGRATOR_SHADE_SHADOW:
- integrator_shade_shadow(INTEGRATOR_STATE_PASS, render_buffer);
- break;
- default:
- kernel_assert(0);
- break;
- }
- }
- else if (INTEGRATOR_STATE(path, queued_kernel)) {
- /* Then handle regular path kernels. */
- switch (INTEGRATOR_STATE(path, queued_kernel)) {
- case DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST:
- integrator_intersect_closest(INTEGRATOR_STATE_PASS);
- break;
- case DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND:
- integrator_shade_background(INTEGRATOR_STATE_PASS, render_buffer);
- break;
- case DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE:
- integrator_shade_surface(INTEGRATOR_STATE_PASS, render_buffer);
- break;
- case DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME:
- integrator_shade_volume(INTEGRATOR_STATE_PASS, render_buffer);
- break;
- case DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE:
- integrator_shade_surface_raytrace(INTEGRATOR_STATE_PASS, render_buffer);
- break;
- case DEVICE_KERNEL_INTEGRATOR_SHADE_LIGHT:
- integrator_shade_light(INTEGRATOR_STATE_PASS, render_buffer);
- break;
- case DEVICE_KERNEL_INTEGRATOR_INTERSECT_SUBSURFACE:
- integrator_intersect_subsurface(INTEGRATOR_STATE_PASS);
- break;
- case DEVICE_KERNEL_INTEGRATOR_INTERSECT_VOLUME_STACK:
- integrator_intersect_volume_stack(INTEGRATOR_STATE_PASS);
- break;
- default:
- kernel_assert(0);
- break;
- }
- }
- else {
- 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 3e4cc837e9b..00000000000
--- a/intern/cycles/kernel/integrator/integrator_shade_background.h
+++ /dev/null
@@ -1,215 +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(INTEGRATOR_STATE_ARGS,
- ccl_global float *ccl_restrict render_buffer)
-{
-#ifdef __BACKGROUND__
- const int shader = kernel_data.background.surface_shader;
- const uint32_t path_flag = INTEGRATOR_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;
- 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(ray, P),
- INTEGRATOR_STATE(ray, D),
- INTEGRATOR_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>(
- INTEGRATOR_STATE_PASS, 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(path, flag) & PATH_RAY_MIS_SKIP) && kernel_data.background.use_mis) {
- const float3 ray_P = INTEGRATOR_STATE(ray, P);
- const float3 ray_D = INTEGRATOR_STATE(ray, D);
- const float mis_ray_pdf = INTEGRATOR_STATE(path, mis_ray_pdf);
- const float mis_ray_t = INTEGRATOR_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(INTEGRATOR_STATE_ARGS,
- 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(path, flag) &
- PATH_RAY_TRANSPARENT_BACKGROUND);
-
- if (is_transparent_background_ray) {
- transparent = average(INTEGRATOR_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(INTEGRATOR_STATE_PASS, render_buffer) :
- zero_float3();
-
- /* When using the ao bounces approximation, adjust background
- * shader intensity with ao factor. */
- if (path_state_ao_bounce(INTEGRATOR_STATE_PASS)) {
- L *= kernel_data.integrator.ao_bounces_factor;
- }
-
- /* Write to render buffer. */
- kernel_accum_background(
- INTEGRATOR_STATE_PASS, L, transparent, is_transparent_background_ray, render_buffer);
-}
-
-ccl_device_inline void integrate_distant_lights(INTEGRATOR_STATE_ARGS,
- ccl_global float *ccl_restrict render_buffer)
-{
- const float3 ray_D = INTEGRATOR_STATE(ray, D);
- const float ray_time = INTEGRATOR_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(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;
- ShaderData *emission_sd = AS_SHADER_DATA(&emission_sd_storage);
- float3 light_eval = light_sample_shader_eval(
- INTEGRATOR_STATE_PASS, 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(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(path, throughput);
- kernel_accum_emission(INTEGRATOR_STATE_PASS, throughput, light_eval, render_buffer);
- }
- }
-}
-
-ccl_device void integrator_shade_background(INTEGRATOR_STATE_ARGS,
- 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(INTEGRATOR_STATE_PASS, render_buffer);
- integrate_background(INTEGRATOR_STATE_PASS, render_buffer);
-
-#ifdef __SHADOW_CATCHER__
- if (INTEGRATOR_STATE(path, flag) & PATH_RAY_SHADOW_CATCHER_BACKGROUND) {
- INTEGRATOR_STATE_WRITE(path, flag) &= ~PATH_RAY_SHADOW_CATCHER_BACKGROUND;
-
- const int isect_prim = INTEGRATOR_STATE(isect, prim);
- const int shader = intersection_get_shader_from_isect_prim(kg, isect_prim);
- const int shader_flags = kernel_tex_fetch(__shaders, shader).flags;
-
- if ((shader_flags & SD_HAS_RAYTRACE) || (kernel_data.film.pass_ao != PASS_UNUSED)) {
- 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 05b530f9665..00000000000
--- a/intern/cycles/kernel/integrator/integrator_shade_light.h
+++ /dev/null
@@ -1,126 +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(INTEGRATOR_STATE_ARGS,
- ccl_global float *ccl_restrict render_buffer)
-{
- /* Setup light sample. */
- Intersection isect ccl_optional_struct_init;
- integrator_state_read_isect(INTEGRATOR_STATE_PASS, &isect);
-
- float3 ray_P = INTEGRATOR_STATE(ray, P);
- const float3 ray_D = INTEGRATOR_STATE(ray, D);
- const float ray_time = INTEGRATOR_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(ray, P) = new_ray_P;
- INTEGRATOR_STATE_WRITE(ray, t) -= isect.t;
-
- /* Set position to where the BSDF was sampled, for correct MIS PDF. */
- const float mis_ray_t = INTEGRATOR_STATE(path, mis_ray_t);
- ray_P -= ray_D * mis_ray_t;
- isect.t += mis_ray_t;
- INTEGRATOR_STATE_WRITE(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(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;
- ShaderData *emission_sd = AS_SHADER_DATA(&emission_sd_storage);
- float3 light_eval = light_sample_shader_eval(INTEGRATOR_STATE_PASS, 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(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(path, throughput);
- kernel_accum_emission(INTEGRATOR_STATE_PASS, throughput, light_eval, render_buffer);
-}
-
-ccl_device void integrator_shade_light(INTEGRATOR_STATE_ARGS,
- ccl_global float *ccl_restrict render_buffer)
-{
- PROFILING_INIT(kg, PROFILING_SHADE_LIGHT_SETUP);
-
- integrate_light(INTEGRATOR_STATE_PASS, 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(path, transparent_bounce) + 1;
- INTEGRATOR_STATE_WRITE(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 fd3c3ae1653..00000000000
--- a/intern/cycles/kernel/integrator/integrator_shade_shadow.h
+++ /dev/null
@@ -1,182 +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 int num_hits)
-{
- return num_hits >= INTEGRATOR_SHADOW_ISECT_SIZE;
-}
-
-#ifdef __TRANSPARENT_SHADOWS__
-ccl_device_inline float3 integrate_transparent_surface_shadow(INTEGRATOR_STATE_ARGS, 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;
- 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(INTEGRATOR_STATE_PASS, &isect, hit);
-
- Ray ray ccl_optional_struct_init;
- integrator_state_read_shadow_ray(INTEGRATOR_STATE_PASS, &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>(
- INTEGRATOR_STATE_PASS, shadow_sd, NULL, PATH_RAY_SHADOW);
- }
-
-# ifdef __VOLUME__
- /* Exit/enter volume. */
- shadow_volume_stack_enter_exit(INTEGRATOR_STATE_PASS, shadow_sd);
-# endif
-
- /* Compute transparency from closures. */
- return shader_bsdf_transparency(kg, shadow_sd);
-}
-
-# ifdef __VOLUME__
-ccl_device_inline void integrate_transparent_volume_shadow(INTEGRATOR_STATE_ARGS,
- const int hit,
- const int num_recorded_hits,
- 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;
- ShaderData *shadow_sd = AS_SHADER_DATA(&shadow_sd_storage);
-
- /* Setup shader data. */
- Ray ray ccl_optional_struct_init;
- integrator_state_read_shadow_ray(INTEGRATOR_STATE_PASS, &ray);
-
- /* Modify ray position and length to match current segment. */
- const float start_t = (hit == 0) ? 0.0f : INTEGRATOR_STATE_ARRAY(shadow_isect, hit - 1, t);
- const float end_t = (hit < num_recorded_hits) ? INTEGRATOR_STATE_ARRAY(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(INTEGRATOR_STATE_PASS, [=](const int i) {
- return integrator_state_read_shadow_volume_stack(INTEGRATOR_STATE_PASS, i);
- });
-
- volume_shadow_heterogeneous(INTEGRATOR_STATE_PASS, &ray, shadow_sd, throughput, step_size);
-}
-# endif
-
-ccl_device_inline bool integrate_transparent_shadow(INTEGRATOR_STATE_ARGS, const int num_hits)
-{
- /* Accumulate shadow for transparent surfaces. */
- const int num_recorded_hits = min(num_hits, INTEGRATOR_SHADOW_ISECT_SIZE);
-
- for (int 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(INTEGRATOR_STATE_PASS)) {
- float3 throughput = INTEGRATOR_STATE(shadow_path, throughput);
- integrate_transparent_volume_shadow(
- INTEGRATOR_STATE_PASS, hit, num_recorded_hits, &throughput);
- if (is_zero(throughput)) {
- return true;
- }
-
- INTEGRATOR_STATE_WRITE(shadow_path, throughput) = throughput;
- }
-# endif
- }
-
- /* Surface shaders. */
- if (hit < num_recorded_hits) {
- const float3 shadow = integrate_transparent_surface_shadow(INTEGRATOR_STATE_PASS, hit);
- const float3 throughput = INTEGRATOR_STATE(shadow_path, throughput) * shadow;
- if (is_zero(throughput)) {
- return true;
- }
-
- INTEGRATOR_STATE_WRITE(shadow_path, throughput) = throughput;
- INTEGRATOR_STATE_WRITE(shadow_path, transparent_bounce) += 1;
- }
-
- /* 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(shadow_isect, num_recorded_hits - 1, t);
- const float3 ray_P = INTEGRATOR_STATE(shadow_ray, P);
- const float3 ray_D = INTEGRATOR_STATE(shadow_ray, D);
- INTEGRATOR_STATE_WRITE(shadow_ray, P) = ray_offset(ray_P + last_hit_t * ray_D, ray_D);
- INTEGRATOR_STATE_WRITE(shadow_ray, t) -= last_hit_t;
- }
-
- return false;
-}
-#endif /* __TRANSPARENT_SHADOWS__ */
-
-ccl_device void integrator_shade_shadow(INTEGRATOR_STATE_ARGS,
- ccl_global float *ccl_restrict render_buffer)
-{
- PROFILING_INIT(kg, PROFILING_SHADE_SHADOW_SETUP);
- const int num_hits = INTEGRATOR_STATE(shadow_path, num_hits);
-
-#ifdef __TRANSPARENT_SHADOWS__
- /* Evaluate transparent shadows. */
- const bool opaque = integrate_transparent_shadow(INTEGRATOR_STATE_PASS, 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(INTEGRATOR_STATE_PASS, 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 a24473addcc..00000000000
--- a/intern/cycles/kernel/integrator/integrator_shade_surface.h
+++ /dev/null
@@ -1,502 +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(INTEGRATOR_STATE_CONST_ARGS,
- ShaderData *sd)
-{
- Intersection isect ccl_optional_struct_init;
- integrator_state_read_isect(INTEGRATOR_STATE_PASS, &isect);
-
- Ray ray ccl_optional_struct_init;
- integrator_state_read_ray(INTEGRATOR_STATE_PASS, &ray);
-
- shader_setup_from_ray(kg, sd, &ray, &isect);
-}
-
-#ifdef __HOLDOUT__
-ccl_device_forceinline bool integrate_surface_holdout(INTEGRATOR_STATE_CONST_ARGS,
- 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(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(path, throughput);
- const float transparent = average(holdout_weight * throughput);
- kernel_accum_transparent(INTEGRATOR_STATE_PASS, 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(INTEGRATOR_STATE_CONST_ARGS,
- const ShaderData *sd,
- ccl_global float *ccl_restrict
- render_buffer)
-{
- const uint32_t path_flag = INTEGRATOR_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(path, mis_ray_pdf);
- const float t = sd->ray_length + INTEGRATOR_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(path, throughput);
- kernel_accum_emission(INTEGRATOR_STATE_PASS, 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(INTEGRATOR_STATE_ARGS,
- ShaderData *sd,
- 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 int path_flag = INTEGRATOR_STATE(path, flag);
- const uint bounce = INTEGRATOR_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;
- ShaderData *emission_sd = AS_SHADER_DATA(&emission_sd_storage);
- const float3 light_eval = light_sample_shader_eval(
- INTEGRATOR_STATE_PASS, 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);
-
- /* Copy volume stack and enter/exit volume. */
- integrator_state_copy_volume_stack_to_shadow(INTEGRATOR_STATE_PASS);
-
- if (is_transmission) {
-# ifdef __VOLUME__
- shadow_volume_stack_enter_exit(INTEGRATOR_STATE_PASS, sd);
-# endif
- }
-
- /* Write shadow ray and associated state to global memory. */
- integrator_state_write_shadow_ray(INTEGRATOR_STATE_PASS, &ray);
-
- /* Copy state from main path to shadow path. */
- const uint16_t bounce = INTEGRATOR_STATE(path, bounce);
- const uint16_t transparent_bounce = INTEGRATOR_STATE(path, transparent_bounce);
- uint32_t shadow_flag = INTEGRATOR_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(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(path, diffuse_glossy_ratio);
- INTEGRATOR_STATE_WRITE(shadow_path, diffuse_glossy_ratio) = diffuse_glossy_ratio;
- }
-
- INTEGRATOR_STATE_WRITE(shadow_path, flag) = shadow_flag;
- INTEGRATOR_STATE_WRITE(shadow_path, bounce) = bounce;
- INTEGRATOR_STATE_WRITE(shadow_path, transparent_bounce) = transparent_bounce;
- INTEGRATOR_STATE_WRITE(shadow_path, throughput) = throughput;
-
- if (kernel_data.kernel_features & KERNEL_FEATURE_SHADOW_PASS) {
- INTEGRATOR_STATE_WRITE(shadow_path, unshadowed_throughput) = throughput;
- }
-
- /* Branch off shadow kernel. */
- INTEGRATOR_SHADOW_PATH_INIT(DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW);
-}
-#endif
-
-/* Path tracing: bounce off or through surface with new direction. */
-ccl_device_forceinline int integrate_surface_bsdf_bssrdf_bounce(INTEGRATOR_STATE_ARGS,
- ShaderData *sd,
- 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);
- 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(INTEGRATOR_STATE_PASS, 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(ray, P) = ray_offset(sd->P, (label & LABEL_TRANSMIT) ? -sd->Ng : sd->Ng);
- INTEGRATOR_STATE_WRITE(ray, D) = normalize(bsdf_omega_in);
- INTEGRATOR_STATE_WRITE(ray, t) = (label & LABEL_TRANSPARENT) ?
- INTEGRATOR_STATE(ray, t) - sd->ray_length :
- FLT_MAX;
-
-#ifdef __RAY_DIFFERENTIALS__
- INTEGRATOR_STATE_WRITE(ray, dP) = differential_make_compact(sd->dP);
- INTEGRATOR_STATE_WRITE(ray, dD) = differential_make_compact(bsdf_domega_in);
-#endif
-
- /* Update throughput. */
- float3 throughput = INTEGRATOR_STATE(path, throughput);
- throughput *= bsdf_eval_sum(&bsdf_eval) / bsdf_pdf;
- INTEGRATOR_STATE_WRITE(path, throughput) = throughput;
-
- if (kernel_data.kernel_features & KERNEL_FEATURE_LIGHT_PASSES) {
- if (INTEGRATOR_STATE(path, bounce) == 0) {
- INTEGRATOR_STATE_WRITE(path,
- diffuse_glossy_ratio) = bsdf_eval_diffuse_glossy_ratio(&bsdf_eval);
- }
- }
-
- /* Update path state */
- if (label & LABEL_TRANSPARENT) {
- INTEGRATOR_STATE_WRITE(path, mis_ray_t) += sd->ray_length;
- }
- else {
- INTEGRATOR_STATE_WRITE(path, mis_ray_pdf) = bsdf_pdf;
- INTEGRATOR_STATE_WRITE(path, mis_ray_t) = 0.0f;
- INTEGRATOR_STATE_WRITE(path, min_ray_pdf) = fminf(bsdf_pdf,
- INTEGRATOR_STATE(path, min_ray_pdf));
- }
-
- path_state_next(INTEGRATOR_STATE_PASS, label);
- return label;
-}
-
-#ifdef __VOLUME__
-ccl_device_forceinline bool integrate_surface_volume_only_bounce(INTEGRATOR_STATE_ARGS,
- ShaderData *sd)
-{
- if (!path_state_volume_next(INTEGRATOR_STATE_PASS)) {
- return LABEL_NONE;
- }
-
- /* Setup ray position, direction stays unchanged. */
- INTEGRATOR_STATE_WRITE(ray, P) = ray_offset(sd->P, -sd->Ng);
-
- /* Clipping works through transparent. */
- INTEGRATOR_STATE_WRITE(ray, t) -= sd->ray_length;
-
-# ifdef __RAY_DIFFERENTIALS__
- INTEGRATOR_STATE_WRITE(ray, dP) = differential_make_compact(sd->dP);
-# endif
-
- INTEGRATOR_STATE_WRITE(path, mis_ray_t) += sd->ray_length;
-
- return LABEL_TRANSMIT | LABEL_TRANSPARENT;
-}
-#endif
-
-#if defined(__AO__) && defined(__SHADER_RAYTRACE__)
-ccl_device_forceinline void integrate_surface_ao_pass(INTEGRATOR_STATE_CONST_ARGS,
- const ShaderData *ccl_restrict sd,
- const RNGState *ccl_restrict rng_state,
- ccl_global float *ccl_restrict render_buffer)
-{
-# ifdef __KERNEL_OPTIX__
- optixDirectCall<void>(2, INTEGRATOR_STATE_PASS, sd, rng_state, render_buffer);
-}
-
-extern "C" __device__ void __direct_callable__ao_pass(INTEGRATOR_STATE_CONST_ARGS,
- const ShaderData *ccl_restrict sd,
- const RNGState *ccl_restrict rng_state,
- ccl_global float *ccl_restrict render_buffer)
-{
-# endif /* __KERNEL_OPTIX__ */
- 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) {
- 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();
-
- Intersection isect ccl_optional_struct_init;
- if (!scene_intersect(kg, &ray, PATH_RAY_SHADOW_OPAQUE, &isect)) {
- ccl_global float *buffer = kernel_pass_pixel_render_buffer(INTEGRATOR_STATE_PASS,
- render_buffer);
- const float3 throughput = INTEGRATOR_STATE(path, throughput);
- kernel_write_pass_float3(buffer + kernel_data.film.pass_ao, throughput);
- }
- }
-}
-#endif /* defined(__AO__) && defined(__SHADER_RAYTRACE__) */
-
-template<uint node_feature_mask>
-ccl_device bool integrate_surface(INTEGRATOR_STATE_ARGS,
- 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(INTEGRATOR_STATE_PASS, &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 int path_flag = INTEGRATOR_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>(INTEGRATOR_STATE_PASS, &sd, render_buffer, path_flag);
- }
-
-#ifdef __SUBSURFACE__
- if (INTEGRATOR_STATE(path, flag) & PATH_RAY_SUBSURFACE) {
- /* When coming from inside subsurface scattering, setup a diffuse
- * closure to perform lighting at the exit point. */
- INTEGRATOR_STATE_WRITE(path, flag) &= ~PATH_RAY_SUBSURFACE;
- subsurface_shader_data_setup(INTEGRATOR_STATE_PASS, &sd);
- }
-#endif
-
- shader_prepare_surface_closures(INTEGRATOR_STATE_PASS, &sd);
-
-#ifdef __HOLDOUT__
- /* Evaluate holdout. */
- if (!integrate_surface_holdout(INTEGRATOR_STATE_PASS, &sd, render_buffer)) {
- return false;
- }
-#endif
-
-#ifdef __EMISSION__
- /* Write emission. */
- if (sd.flag & SD_EMISSION) {
- integrate_surface_emission(INTEGRATOR_STATE_PASS, &sd, render_buffer);
- }
-#endif
-
-#ifdef __PASSES__
- /* Write render passes. */
- PROFILING_EVENT(PROFILING_SHADE_SURFACE_PASSES);
- kernel_write_data_passes(INTEGRATOR_STATE_PASS, &sd, render_buffer);
-#endif
-
- /* Load random number state. */
- RNGState rng_state;
- path_state_rng_load(INTEGRATOR_STATE_PASS, &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(INTEGRATOR_STATE_PASS,
- path_flag);
- if (probability == 0.0f) {
- return false;
- }
- else if (probability != 1.0f) {
- INTEGRATOR_STATE_WRITE(path, throughput) /= probability;
- }
- }
-
-#ifdef __DENOISING_FEATURES__
- kernel_write_denoising_features_surface(INTEGRATOR_STATE_PASS, &sd, render_buffer);
-#endif
-
-#ifdef __SHADOW_CATCHER__
- kernel_write_shadow_catcher_bounce_data(INTEGRATOR_STATE_PASS, &sd, render_buffer);
-#endif
-
- /* Direct light. */
- PROFILING_EVENT(PROFILING_SHADE_SURFACE_DIRECT_LIGHT);
- integrate_surface_direct_light(INTEGRATOR_STATE_PASS, &sd, &rng_state);
-
-#if defined(__AO__) && defined(__SHADER_RAYTRACE__)
- /* Ambient occlusion pass. */
- if (node_feature_mask & KERNEL_FEATURE_NODE_RAYTRACE) {
- if ((kernel_data.film.pass_ao != PASS_UNUSED) &&
- (INTEGRATOR_STATE(path, flag) & PATH_RAY_CAMERA)) {
- PROFILING_EVENT(PROFILING_SHADE_SURFACE_AO);
- integrate_surface_ao_pass(INTEGRATOR_STATE_PASS, &sd, &rng_state, render_buffer);
- }
- }
-#endif
-
- PROFILING_EVENT(PROFILING_SHADE_SURFACE_INDIRECT_LIGHT);
- continue_path_label = integrate_surface_bsdf_bssrdf_bounce(
- INTEGRATOR_STATE_PASS, &sd, &rng_state);
-#ifdef __VOLUME__
- }
- else {
- PROFILING_EVENT(PROFILING_SHADE_SURFACE_INDIRECT_LIGHT);
- continue_path_label = integrate_surface_volume_only_bounce(INTEGRATOR_STATE_PASS, &sd);
- }
-
- if (continue_path_label & LABEL_TRANSMIT) {
- /* Enter/Exit volume. */
- volume_stack_enter_exit(INTEGRATOR_STATE_PASS, &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(INTEGRATOR_STATE_ARGS,
- ccl_global float *ccl_restrict render_buffer)
-{
- if (integrate_surface<node_feature_mask>(INTEGRATOR_STATE_PASS, render_buffer)) {
- if (INTEGRATOR_STATE(path, flag) & PATH_RAY_SUBSURFACE) {
- INTEGRATOR_PATH_NEXT(current_kernel, DEVICE_KERNEL_INTEGRATOR_INTERSECT_SUBSURFACE);
- }
- else {
- kernel_assert(INTEGRATOR_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(
- INTEGRATOR_STATE_ARGS, ccl_global float *ccl_restrict render_buffer)
-{
- integrator_shade_surface<KERNEL_FEATURE_NODE_MASK_SURFACE,
- DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE>(INTEGRATOR_STATE_PASS,
- 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 dac3efb3996..00000000000
--- a/intern/cycles/kernel/integrator/integrator_shade_volume.h
+++ /dev/null
@@ -1,1019 +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(INTEGRATOR_STATE_ARGS,
- ShaderData *ccl_restrict sd,
- float3 *ccl_restrict extinction)
-{
- shader_eval_volume<true>(INTEGRATOR_STATE_PASS, sd, PATH_RAY_SHADOW, [=](const int i) {
- return integrator_state_read_shadow_volume_stack(INTEGRATOR_STATE_PASS, 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(INTEGRATOR_STATE_ARGS,
- ShaderData *ccl_restrict sd,
- VolumeShaderCoefficients *coeff)
-{
- const int path_flag = INTEGRATOR_STATE(path, flag);
- shader_eval_volume<false>(INTEGRATOR_STATE_PASS, sd, path_flag, [=](const int i) {
- return integrator_state_read_volume_stack(INTEGRATOR_STATE_PASS, 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++) {
- 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(const KernelGlobals *kg,
- const RNGState *rng_state,
- const float object_step_size,
- float t,
- float *step_size,
- float *step_shade_offset,
- float *steps_offset,
- 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(INTEGRATOR_STATE_ARGS,
- Ray *ccl_restrict ray,
- ShaderData *ccl_restrict sd,
- float3 *ccl_restrict throughput)
-{
- float3 sigma_t = zero_float3();
-
- if (shadow_volume_shader_sample(INTEGRATOR_STATE_PASS, 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(INTEGRATOR_STATE_ARGS,
- Ray *ccl_restrict ray,
- ShaderData *ccl_restrict sd,
- float3 *ccl_restrict throughput,
- const float object_step_size)
-{
- /* Load random number state. */
- RNGState rng_state;
- shadow_path_state_rng_load(INTEGRATOR_STATE_PASS, &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(INTEGRATOR_STATE_PASS, 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(const Ray *ccl_restrict ray,
- const float3 light_P,
- const float xi,
- 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(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(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, float3 *transmittance, 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(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(
- const ShaderData *sd,
- const Ray *ray,
- const float3 equiangular_light_P,
- const VolumeShaderCoefficients &ccl_restrict coeff,
- const float3 transmittance,
- VolumeIntegrateState &ccl_restrict vstate,
- 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(
- INTEGRATOR_STATE_ARGS,
- Ray *ccl_restrict ray,
- ShaderData *ccl_restrict sd,
- 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,
- 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(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(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(INTEGRATOR_STATE_PASS, 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(
- INTEGRATOR_STATE_PASS, result.indirect_throughput, accum_emission, render_buffer);
- }
-
-# ifdef __DENOISING_FEATURES__
- /* Write denoising features. */
- if (write_denoising_features) {
- kernel_write_denoising_features_volume(
- INTEGRATOR_STATE_PASS, 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(INTEGRATOR_STATE_ARGS,
- const ShaderData *ccl_restrict sd,
- const RNGState *ccl_restrict rng_state,
- 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 int path_flag = INTEGRATOR_STATE(path, flag);
- const uint bounce = INTEGRATOR_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(INTEGRATOR_STATE_ARGS,
- const ShaderData *ccl_restrict sd,
- const RNGState *ccl_restrict rng_state,
- const float3 P,
- const ShaderVolumePhases *ccl_restrict
- phases,
- const float3 throughput,
- 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 int path_flag = INTEGRATOR_STATE(path, flag);
- const uint bounce = INTEGRATOR_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;
- ShaderData *emission_sd = AS_SHADER_DATA(&emission_sd_storage);
- const float3 light_eval = light_sample_shader_eval(
- INTEGRATOR_STATE_PASS, 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);
-
- /* Write shadow ray and associated state to global memory. */
- integrator_state_write_shadow_ray(INTEGRATOR_STATE_PASS, &ray);
-
- /* Copy state from main path to shadow path. */
- const uint16_t bounce = INTEGRATOR_STATE(path, bounce);
- const uint16_t transparent_bounce = INTEGRATOR_STATE(path, transparent_bounce);
- uint32_t shadow_flag = INTEGRATOR_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(path, diffuse_glossy_ratio);
- INTEGRATOR_STATE_WRITE(shadow_path, diffuse_glossy_ratio) = diffuse_glossy_ratio;
- }
-
- INTEGRATOR_STATE_WRITE(shadow_path, flag) = shadow_flag;
- INTEGRATOR_STATE_WRITE(shadow_path, bounce) = bounce;
- INTEGRATOR_STATE_WRITE(shadow_path, transparent_bounce) = transparent_bounce;
- INTEGRATOR_STATE_WRITE(shadow_path, throughput) = throughput_phase;
-
- if (kernel_data.kernel_features & KERNEL_FEATURE_SHADOW_PASS) {
- INTEGRATOR_STATE_WRITE(shadow_path, unshadowed_throughput) = throughput;
- }
-
- integrator_state_copy_volume_stack_to_shadow(INTEGRATOR_STATE_PASS);
-
- /* Branch off shadow kernel. */
- INTEGRATOR_SHADOW_PATH_INIT(DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW);
-}
-# endif
-
-/* Path tracing: scatter in new direction using phase function */
-ccl_device_forceinline bool integrate_volume_phase_scatter(INTEGRATOR_STATE_ARGS,
- ShaderData *sd,
- const RNGState *rng_state,
- 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(ray, P) = sd->P;
- INTEGRATOR_STATE_WRITE(ray, D) = normalize(phase_omega_in);
- INTEGRATOR_STATE_WRITE(ray, t) = FLT_MAX;
-
-# ifdef __RAY_DIFFERENTIALS__
- INTEGRATOR_STATE_WRITE(ray, dP) = differential_make_compact(sd->dP);
- INTEGRATOR_STATE_WRITE(ray, dD) = differential_make_compact(phase_domega_in);
-# endif
-
- /* Update throughput. */
- const float3 throughput = INTEGRATOR_STATE(path, throughput);
- const float3 throughput_phase = throughput * bsdf_eval_sum(&phase_eval) / phase_pdf;
- INTEGRATOR_STATE_WRITE(path, throughput) = throughput_phase;
-
- if (kernel_data.kernel_features & KERNEL_FEATURE_LIGHT_PASSES) {
- INTEGRATOR_STATE_WRITE(path, diffuse_glossy_ratio) = one_float3();
- }
-
- /* Update path state */
- INTEGRATOR_STATE_WRITE(path, mis_ray_pdf) = phase_pdf;
- INTEGRATOR_STATE_WRITE(path, mis_ray_t) = 0.0f;
- INTEGRATOR_STATE_WRITE(path, min_ray_pdf) = fminf(phase_pdf,
- INTEGRATOR_STATE(path, min_ray_pdf));
-
- path_state_next(INTEGRATOR_STATE_PASS, 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(INTEGRATOR_STATE_ARGS,
- 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(INTEGRATOR_STATE_PASS, &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(path, flag) & PATH_RAY_TERMINATE);
- const bool have_equiangular_sample = need_light_sample &&
- integrate_volume_sample_light(
- INTEGRATOR_STATE_PASS, &sd, &rng_state, &ls) &&
- (ls.t != FLT_MAX);
-
- VolumeSampleMethod direct_sample_method = (have_equiangular_sample) ?
- volume_stack_sample_method(INTEGRATOR_STATE_PASS) :
- VOLUME_SAMPLE_DISTANCE;
-
- /* Step through volume. */
- const float step_size = volume_stack_step_size(INTEGRATOR_STATE_PASS, [=](const int i) {
- return integrator_state_read_volume_stack(INTEGRATOR_STATE_PASS, i);
- });
-
- /* TODO: expensive to zero closures? */
- VolumeIntegrateResult result = {};
- volume_integrate_heterogeneous(INTEGRATOR_STATE_PASS,
- 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(path, flag);
- const float probability = (path_flag & PATH_RAY_TERMINATE_IN_NEXT_VOLUME) ?
- 0.0f :
- path_state_continuation_probability(INTEGRATOR_STATE_PASS,
- 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(INTEGRATOR_STATE_PASS,
- &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(path, throughput) = result.indirect_throughput;
-
- if (result.indirect_scatter) {
- sd.P = ray->P + result.indirect_t * ray->D;
-
- if (integrate_volume_phase_scatter(
- INTEGRATOR_STATE_PASS, &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(INTEGRATOR_STATE_ARGS,
- 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(INTEGRATOR_STATE_PASS, &ray);
-
- Intersection isect ccl_optional_struct_init;
- integrator_state_read_isect(INTEGRATOR_STATE_PASS, &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(INTEGRATOR_STATE_PASS);
- }
-
- VolumeIntegrateEvent event = volume_integrate(INTEGRATOR_STATE_PASS, &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>(
- INTEGRATOR_STATE_PASS, &isect, shader, flags);
- return;
- }
- }
-#endif /* __VOLUME__ */
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/integrator/integrator_state.h b/intern/cycles/kernel/integrator/integrator_state.h
deleted file mode 100644
index 094446be02c..00000000000
--- a/intern/cycles/kernel/integrator/integrator_state.h
+++ /dev/null
@@ -1,185 +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.
- *
- * INTEGRATOR_STATE_ARGS: prepend to argument definitions for every function that accesses
- * path state.
- * INTEGRATOR_STATE_CONST_ARGS: same as INTEGRATOR_STATE_ARGS, when state is read-only
- * INTEGRATOR_STATE_PASS: use to pass along state to other functions access it.
- *
- * INTEGRATOR_STATE(x, y): read nested struct member x.y of IntegratorState
- * INTEGRATOR_STATE_WRITE(x, y): write to nested struct member x.y of IntegratorState
- *
- * INTEGRATOR_STATE_ARRAY(x, index, y): read x[index].y
- * INTEGRATOR_STATE_ARRAY_WRITE(x, index, y): write x[index].y
- *
- * INTEGRATOR_STATE_COPY(to_x, from_x): copy contents of one nested struct to another
- *
- * INTEGRATOR_STATE_IS_NULL: test if any integrator state is available, for shader evaluation
- * INTEGRATOR_STATE_PASS_NULL: use to pass empty state to other functions.
- *
- * NOTE: if we end up with a device that passes no arguments, the leading comma will be a problem.
- * Can solve it with more macros if we encounter it, but rather ugly so postpone for now.
- */
-
-#include "kernel/kernel_types.h"
-
-#include "util/util_types.h"
-
-#pragma once
-
-CCL_NAMESPACE_BEGIN
-
-/* Constants
- *
- * TODO: these could be made dynamic depending on the features used in the scene. */
-
-#define INTEGRATOR_VOLUME_STACK_SIZE VOLUME_STACK_SIZE
-#define INTEGRATOR_SHADOW_ISECT_SIZE 4
-
-/* Data structures */
-
-/* Integrator State
- *
- * CPU rendering path state with AoS layout. */
-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, size) \
- } \
- name[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
-} 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) type *name;
-#define KERNEL_STRUCT_ARRAY_MEMBER KERNEL_STRUCT_MEMBER
-#define KERNEL_STRUCT_END(name) \
- } \
- name;
-#define KERNEL_STRUCT_END_ARRAY(name, size) \
- } \
- name[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
-
- /* Count number of queued kernels. */
- IntegratorQueueCounter *queue_counter;
-
- /* Count number of kernels queued for specific shaders. */
- int *sort_key_counter[DEVICE_KERNEL_INTEGRATOR_NUM];
-
- /* Index of path which will be used by a next shadow catcher split. */
- int *next_shadow_catcher_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;
-
-# define INTEGRATOR_STATE_ARGS \
- ccl_attr_maybe_unused const KernelGlobals *ccl_restrict kg, \
- IntegratorStateCPU *ccl_restrict state
-# define INTEGRATOR_STATE_CONST_ARGS \
- ccl_attr_maybe_unused const KernelGlobals *ccl_restrict kg, \
- const IntegratorStateCPU *ccl_restrict state
-# define INTEGRATOR_STATE_PASS kg, state
-
-# define INTEGRATOR_STATE_PASS_NULL kg, NULL
-# define INTEGRATOR_STATE_IS_NULL (state == NULL)
-
-# define INTEGRATOR_STATE(nested_struct, member) \
- (((const IntegratorStateCPU *)state)->nested_struct.member)
-# define INTEGRATOR_STATE_WRITE(nested_struct, member) (state->nested_struct.member)
-
-# define INTEGRATOR_STATE_ARRAY(nested_struct, array_index, member) \
- (((const IntegratorStateCPU *)state)->nested_struct[array_index].member)
-# define INTEGRATOR_STATE_ARRAY_WRITE(nested_struct, array_index, member) \
- ((state)->nested_struct[array_index].member)
-
-#else /* __KERNEL_CPU__ */
-
-/* Array access on GPU with Structure-of-Arrays. */
-
-typedef int IntegratorState;
-
-# define INTEGRATOR_STATE_ARGS const KernelGlobals *ccl_restrict kg, const IntegratorState state
-# define INTEGRATOR_STATE_CONST_ARGS \
- const KernelGlobals *ccl_restrict kg, const IntegratorState state
-# define INTEGRATOR_STATE_PASS kg, state
-
-# define INTEGRATOR_STATE_PASS_NULL kg, -1
-# define INTEGRATOR_STATE_IS_NULL (state == -1)
-
-# define INTEGRATOR_STATE(nested_struct, member) \
- kernel_integrator_state.nested_struct.member[state]
-# define INTEGRATOR_STATE_WRITE(nested_struct, member) INTEGRATOR_STATE(nested_struct, member)
-
-# define INTEGRATOR_STATE_ARRAY(nested_struct, array_index, member) \
- kernel_integrator_state.nested_struct[array_index].member[state]
-# define INTEGRATOR_STATE_ARRAY_WRITE(nested_struct, array_index, member) \
- INTEGRATOR_STATE_ARRAY(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 8477efd7b66..00000000000
--- a/intern/cycles/kernel/integrator/integrator_state_flow.h
+++ /dev/null
@@ -1,144 +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(path, queued_kernel) == 0)
-#define INTEGRATOR_SHADOW_PATH_IS_TERMINATED (INTEGRATOR_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(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(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(path, queued_kernel) = 0;
-
-# define INTEGRATOR_SHADOW_PATH_INIT(next_kernel) \
- atomic_fetch_and_add_uint32(&kernel_integrator_state.queue_counter->num_queued[next_kernel], \
- 1); \
- INTEGRATOR_STATE_WRITE(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(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(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(path, queued_kernel) = next_kernel; \
- INTEGRATOR_STATE_WRITE(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(path, queued_kernel) = next_kernel; \
- INTEGRATOR_STATE_WRITE(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(path, queued_kernel) = next_kernel;
-# define INTEGRATOR_PATH_INIT_SORTED(next_kernel, key) \
- { \
- INTEGRATOR_STATE_WRITE(path, queued_kernel) = next_kernel; \
- (void)key; \
- }
-# define INTEGRATOR_PATH_NEXT(current_kernel, next_kernel) \
- { \
- INTEGRATOR_STATE_WRITE(path, queued_kernel) = next_kernel; \
- (void)current_kernel; \
- }
-# define INTEGRATOR_PATH_TERMINATE(current_kernel) \
- { \
- INTEGRATOR_STATE_WRITE(path, queued_kernel) = 0; \
- (void)current_kernel; \
- }
-# define INTEGRATOR_PATH_NEXT_SORTED(current_kernel, next_kernel, key) \
- { \
- INTEGRATOR_STATE_WRITE(path, queued_kernel) = next_kernel; \
- (void)key; \
- (void)current_kernel; \
- }
-
-# define INTEGRATOR_SHADOW_PATH_INIT(next_kernel) \
- INTEGRATOR_STATE_WRITE(shadow_path, queued_kernel) = next_kernel;
-# define INTEGRATOR_SHADOW_PATH_NEXT(current_kernel, next_kernel) \
- { \
- INTEGRATOR_STATE_WRITE(shadow_path, queued_kernel) = next_kernel; \
- (void)current_kernel; \
- }
-# define INTEGRATOR_SHADOW_PATH_TERMINATE(current_kernel) \
- { \
- INTEGRATOR_STATE_WRITE(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/integrator_state_template.h
deleted file mode 100644
index 41dd1bfcdbf..00000000000
--- a/intern/cycles/kernel/integrator/integrator_state_template.h
+++ /dev/null
@@ -1,163 +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.
- */
-
-/************************************ Path State *****************************/
-
-KERNEL_STRUCT_BEGIN(path)
-/* Index of a pixel within the device render buffer where this path will write its result.
- * To get an actual offset within the buffer the value needs to be multiplied by the
- * `kernel_data.film.pass_stride`.
- *
- * The multiplication is delayed for later, so that state can use 32bit integer. */
-KERNEL_STRUCT_MEMBER(path, uint32_t, render_pixel_index, KERNEL_FEATURE_PATH_TRACING)
-/* Current sample number. */
-KERNEL_STRUCT_MEMBER(path, uint16_t, sample, KERNEL_FEATURE_PATH_TRACING)
-/* Current ray bounce depth. */
-KERNEL_STRUCT_MEMBER(path, uint16_t, bounce, KERNEL_FEATURE_PATH_TRACING)
-/* Current diffuse ray bounce depth. */
-KERNEL_STRUCT_MEMBER(path, uint16_t, diffuse_bounce, KERNEL_FEATURE_PATH_TRACING)
-/* Current glossy ray bounce depth. */
-KERNEL_STRUCT_MEMBER(path, uint16_t, glossy_bounce, KERNEL_FEATURE_PATH_TRACING)
-/* Current transmission ray bounce depth. */
-KERNEL_STRUCT_MEMBER(path, uint16_t, transmission_bounce, KERNEL_FEATURE_PATH_TRACING)
-/* Current volume ray bounce depth. */
-KERNEL_STRUCT_MEMBER(path, uint16_t, volume_bounce, KERNEL_FEATURE_PATH_TRACING)
-/* Current volume bounds ray bounce depth. */
-KERNEL_STRUCT_MEMBER(path, uint16_t, volume_bounds_bounce, KERNEL_FEATURE_PATH_TRACING)
-/* Current transparent ray bounce depth. */
-KERNEL_STRUCT_MEMBER(path, uint16_t, transparent_bounce, KERNEL_FEATURE_PATH_TRACING)
-/* DeviceKernel bit indicating queued kernels.
- * TODO: reduce size? */
-KERNEL_STRUCT_MEMBER(path, uint32_t, queued_kernel, KERNEL_FEATURE_PATH_TRACING)
-/* Random number generator seed. */
-KERNEL_STRUCT_MEMBER(path, uint32_t, rng_hash, KERNEL_FEATURE_PATH_TRACING)
-/* Random number dimension offset. */
-KERNEL_STRUCT_MEMBER(path, uint32_t, rng_offset, KERNEL_FEATURE_PATH_TRACING)
-/* enum PathRayFlag */
-KERNEL_STRUCT_MEMBER(path, uint32_t, flag, KERNEL_FEATURE_PATH_TRACING)
-/* Multiple importance sampling
- * The PDF of BSDF sampling at the last scatter point, and distance to the
- * last scatter point minus the last ray segment. This distance lets us
- * compute the complete distance through transparent surfaces and volumes. */
-KERNEL_STRUCT_MEMBER(path, float, mis_ray_pdf, KERNEL_FEATURE_PATH_TRACING)
-KERNEL_STRUCT_MEMBER(path, float, mis_ray_t, KERNEL_FEATURE_PATH_TRACING)
-/* Filter glossy. */
-KERNEL_STRUCT_MEMBER(path, float, min_ray_pdf, KERNEL_FEATURE_PATH_TRACING)
-/* Throughput. */
-KERNEL_STRUCT_MEMBER(path, float3, throughput, KERNEL_FEATURE_PATH_TRACING)
-/* Ratio of throughput to distinguish diffuse and glossy render passes. */
-KERNEL_STRUCT_MEMBER(path, float3, diffuse_glossy_ratio, KERNEL_FEATURE_LIGHT_PASSES)
-/* Denoising. */
-KERNEL_STRUCT_MEMBER(path, float3, denoising_feature_throughput, KERNEL_FEATURE_DENOISING)
-/* Shader sorting. */
-/* TODO: compress as uint16? or leave out entirely and recompute key in sorting code? */
-KERNEL_STRUCT_MEMBER(path, uint32_t, shader_sort_key, KERNEL_FEATURE_PATH_TRACING)
-KERNEL_STRUCT_END(path)
-
-/************************************** Ray ***********************************/
-
-KERNEL_STRUCT_BEGIN(ray)
-KERNEL_STRUCT_MEMBER(ray, float3, P, KERNEL_FEATURE_PATH_TRACING)
-KERNEL_STRUCT_MEMBER(ray, float3, D, KERNEL_FEATURE_PATH_TRACING)
-KERNEL_STRUCT_MEMBER(ray, float, t, KERNEL_FEATURE_PATH_TRACING)
-KERNEL_STRUCT_MEMBER(ray, float, time, KERNEL_FEATURE_PATH_TRACING)
-KERNEL_STRUCT_MEMBER(ray, float, dP, KERNEL_FEATURE_PATH_TRACING)
-KERNEL_STRUCT_MEMBER(ray, float, dD, KERNEL_FEATURE_PATH_TRACING)
-KERNEL_STRUCT_END(ray)
-
-/*************************** Intersection result ******************************/
-
-/* Result from scene intersection. */
-KERNEL_STRUCT_BEGIN(isect)
-KERNEL_STRUCT_MEMBER(isect, float, t, KERNEL_FEATURE_PATH_TRACING)
-KERNEL_STRUCT_MEMBER(isect, float, u, KERNEL_FEATURE_PATH_TRACING)
-KERNEL_STRUCT_MEMBER(isect, float, v, KERNEL_FEATURE_PATH_TRACING)
-KERNEL_STRUCT_MEMBER(isect, int, prim, KERNEL_FEATURE_PATH_TRACING)
-KERNEL_STRUCT_MEMBER(isect, int, object, KERNEL_FEATURE_PATH_TRACING)
-KERNEL_STRUCT_MEMBER(isect, int, type, KERNEL_FEATURE_PATH_TRACING)
-/* TODO: exclude for GPU. */
-KERNEL_STRUCT_MEMBER(isect, float3, Ng, KERNEL_FEATURE_PATH_TRACING)
-KERNEL_STRUCT_END(isect)
-
-/*************** Subsurface closure state for subsurface kernel ***************/
-
-KERNEL_STRUCT_BEGIN(subsurface)
-KERNEL_STRUCT_MEMBER(subsurface, float3, albedo, KERNEL_FEATURE_SUBSURFACE)
-KERNEL_STRUCT_MEMBER(subsurface, float3, radius, KERNEL_FEATURE_SUBSURFACE)
-KERNEL_STRUCT_MEMBER(subsurface, float, anisotropy, KERNEL_FEATURE_SUBSURFACE)
-KERNEL_STRUCT_MEMBER(subsurface, float, roughness, KERNEL_FEATURE_SUBSURFACE)
-KERNEL_STRUCT_END(subsurface)
-
-/********************************** Volume Stack ******************************/
-
-KERNEL_STRUCT_BEGIN(volume_stack)
-KERNEL_STRUCT_ARRAY_MEMBER(volume_stack, int, object, KERNEL_FEATURE_VOLUME)
-KERNEL_STRUCT_ARRAY_MEMBER(volume_stack, int, shader, KERNEL_FEATURE_VOLUME)
-KERNEL_STRUCT_END_ARRAY(volume_stack, INTEGRATOR_VOLUME_STACK_SIZE)
-
-/********************************* Shadow Path State **************************/
-
-KERNEL_STRUCT_BEGIN(shadow_path)
-/* 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)
-/* DeviceKernel bit indicating queued kernels.
- * TODO: reduce size? */
-KERNEL_STRUCT_MEMBER(shadow_path, uint32_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)
-/* TODO: exclude for GPU. */
-KERNEL_STRUCT_ARRAY_MEMBER(shadow_isect, float3, Ng, KERNEL_FEATURE_PATH_TRACING)
-KERNEL_STRUCT_END_ARRAY(shadow_isect, INTEGRATOR_SHADOW_ISECT_SIZE)
-
-/**************************** 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, INTEGRATOR_VOLUME_STACK_SIZE)
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 cdf412fe22f..00000000000
--- a/intern/cycles/kernel/integrator/integrator_state_util.h
+++ /dev/null
@@ -1,273 +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(INTEGRATOR_STATE_ARGS,
- const Ray *ccl_restrict ray)
-{
- INTEGRATOR_STATE_WRITE(ray, P) = ray->P;
- INTEGRATOR_STATE_WRITE(ray, D) = ray->D;
- INTEGRATOR_STATE_WRITE(ray, t) = ray->t;
- INTEGRATOR_STATE_WRITE(ray, time) = ray->time;
- INTEGRATOR_STATE_WRITE(ray, dP) = ray->dP;
- INTEGRATOR_STATE_WRITE(ray, dD) = ray->dD;
-}
-
-ccl_device_forceinline void integrator_state_read_ray(INTEGRATOR_STATE_CONST_ARGS,
- Ray *ccl_restrict ray)
-{
- ray->P = INTEGRATOR_STATE(ray, P);
- ray->D = INTEGRATOR_STATE(ray, D);
- ray->t = INTEGRATOR_STATE(ray, t);
- ray->time = INTEGRATOR_STATE(ray, time);
- ray->dP = INTEGRATOR_STATE(ray, dP);
- ray->dD = INTEGRATOR_STATE(ray, dD);
-}
-
-/* Shadow Ray */
-
-ccl_device_forceinline void integrator_state_write_shadow_ray(INTEGRATOR_STATE_ARGS,
- const Ray *ccl_restrict ray)
-{
- INTEGRATOR_STATE_WRITE(shadow_ray, P) = ray->P;
- INTEGRATOR_STATE_WRITE(shadow_ray, D) = ray->D;
- INTEGRATOR_STATE_WRITE(shadow_ray, t) = ray->t;
- INTEGRATOR_STATE_WRITE(shadow_ray, time) = ray->time;
- INTEGRATOR_STATE_WRITE(shadow_ray, dP) = ray->dP;
-}
-
-ccl_device_forceinline void integrator_state_read_shadow_ray(INTEGRATOR_STATE_CONST_ARGS,
- Ray *ccl_restrict ray)
-{
- ray->P = INTEGRATOR_STATE(shadow_ray, P);
- ray->D = INTEGRATOR_STATE(shadow_ray, D);
- ray->t = INTEGRATOR_STATE(shadow_ray, t);
- ray->time = INTEGRATOR_STATE(shadow_ray, time);
- ray->dP = INTEGRATOR_STATE(shadow_ray, dP);
- ray->dD = differential_zero_compact();
-}
-
-/* Intersection */
-
-ccl_device_forceinline void integrator_state_write_isect(INTEGRATOR_STATE_ARGS,
- const Intersection *ccl_restrict isect)
-{
- INTEGRATOR_STATE_WRITE(isect, t) = isect->t;
- INTEGRATOR_STATE_WRITE(isect, u) = isect->u;
- INTEGRATOR_STATE_WRITE(isect, v) = isect->v;
- INTEGRATOR_STATE_WRITE(isect, object) = isect->object;
- INTEGRATOR_STATE_WRITE(isect, prim) = isect->prim;
- INTEGRATOR_STATE_WRITE(isect, type) = isect->type;
-#ifdef __EMBREE__
- INTEGRATOR_STATE_WRITE(isect, Ng) = isect->Ng;
-#endif
-}
-
-ccl_device_forceinline void integrator_state_read_isect(INTEGRATOR_STATE_CONST_ARGS,
- Intersection *ccl_restrict isect)
-{
- isect->prim = INTEGRATOR_STATE(isect, prim);
- isect->object = INTEGRATOR_STATE(isect, object);
- isect->type = INTEGRATOR_STATE(isect, type);
- isect->u = INTEGRATOR_STATE(isect, u);
- isect->v = INTEGRATOR_STATE(isect, v);
- isect->t = INTEGRATOR_STATE(isect, t);
-#ifdef __EMBREE__
- isect->Ng = INTEGRATOR_STATE(isect, Ng);
-#endif
-}
-
-ccl_device_forceinline VolumeStack integrator_state_read_volume_stack(INTEGRATOR_STATE_CONST_ARGS,
- int i)
-{
- VolumeStack entry = {INTEGRATOR_STATE_ARRAY(volume_stack, i, object),
- INTEGRATOR_STATE_ARRAY(volume_stack, i, shader)};
- return entry;
-}
-
-ccl_device_forceinline void integrator_state_write_volume_stack(INTEGRATOR_STATE_ARGS,
- int i,
- VolumeStack entry)
-{
- INTEGRATOR_STATE_ARRAY_WRITE(volume_stack, i, object) = entry.object;
- INTEGRATOR_STATE_ARRAY_WRITE(volume_stack, i, shader) = entry.shader;
-}
-
-ccl_device_forceinline bool integrator_state_volume_stack_is_empty(INTEGRATOR_STATE_CONST_ARGS)
-{
- return (kernel_data.kernel_features & KERNEL_FEATURE_VOLUME) ?
- INTEGRATOR_STATE_ARRAY(volume_stack, 0, shader) == SHADER_NONE :
- true;
-}
-
-/* Shadow Intersection */
-
-ccl_device_forceinline void integrator_state_write_shadow_isect(
- INTEGRATOR_STATE_ARGS, const Intersection *ccl_restrict isect, const int index)
-{
- INTEGRATOR_STATE_ARRAY_WRITE(shadow_isect, index, t) = isect->t;
- INTEGRATOR_STATE_ARRAY_WRITE(shadow_isect, index, u) = isect->u;
- INTEGRATOR_STATE_ARRAY_WRITE(shadow_isect, index, v) = isect->v;
- INTEGRATOR_STATE_ARRAY_WRITE(shadow_isect, index, object) = isect->object;
- INTEGRATOR_STATE_ARRAY_WRITE(shadow_isect, index, prim) = isect->prim;
- INTEGRATOR_STATE_ARRAY_WRITE(shadow_isect, index, type) = isect->type;
-#ifdef __EMBREE__
- INTEGRATOR_STATE_ARRAY_WRITE(shadow_isect, index, Ng) = isect->Ng;
-#endif
-}
-
-ccl_device_forceinline void integrator_state_read_shadow_isect(INTEGRATOR_STATE_CONST_ARGS,
- Intersection *ccl_restrict isect,
- const int index)
-{
- isect->prim = INTEGRATOR_STATE_ARRAY(shadow_isect, index, prim);
- isect->object = INTEGRATOR_STATE_ARRAY(shadow_isect, index, object);
- isect->type = INTEGRATOR_STATE_ARRAY(shadow_isect, index, type);
- isect->u = INTEGRATOR_STATE_ARRAY(shadow_isect, index, u);
- isect->v = INTEGRATOR_STATE_ARRAY(shadow_isect, index, v);
- isect->t = INTEGRATOR_STATE_ARRAY(shadow_isect, index, t);
-#ifdef __EMBREE__
- isect->Ng = INTEGRATOR_STATE_ARRAY(shadow_isect, index, Ng);
-#endif
-}
-
-ccl_device_forceinline void integrator_state_copy_volume_stack_to_shadow(INTEGRATOR_STATE_ARGS)
-{
- if (kernel_data.kernel_features & KERNEL_FEATURE_VOLUME) {
- for (int i = 0; i < INTEGRATOR_VOLUME_STACK_SIZE; i++) {
- INTEGRATOR_STATE_ARRAY_WRITE(shadow_volume_stack, i, object) = INTEGRATOR_STATE_ARRAY(
- volume_stack, i, object);
- INTEGRATOR_STATE_ARRAY_WRITE(shadow_volume_stack, i, shader) = INTEGRATOR_STATE_ARRAY(
- volume_stack, i, shader);
- }
- }
-}
-
-ccl_device_forceinline VolumeStack
-integrator_state_read_shadow_volume_stack(INTEGRATOR_STATE_CONST_ARGS, int i)
-{
- VolumeStack entry = {INTEGRATOR_STATE_ARRAY(shadow_volume_stack, i, object),
- INTEGRATOR_STATE_ARRAY(shadow_volume_stack, i, shader)};
- return entry;
-}
-
-ccl_device_forceinline bool integrator_state_shadow_volume_stack_is_empty(
- INTEGRATOR_STATE_CONST_ARGS)
-{
- return (kernel_data.kernel_features & KERNEL_FEATURE_VOLUME) ?
- INTEGRATOR_STATE_ARRAY(shadow_volume_stack, 0, shader) == SHADER_NONE :
- true;
-}
-
-ccl_device_forceinline void integrator_state_write_shadow_volume_stack(INTEGRATOR_STATE_ARGS,
- int i,
- VolumeStack entry)
-{
- INTEGRATOR_STATE_ARRAY_WRITE(shadow_volume_stack, i, object) = entry.object;
- INTEGRATOR_STATE_ARRAY_WRITE(shadow_volume_stack, i, shader) = entry.shader;
-}
-
-#if defined(__KERNEL_GPU__)
-ccl_device_inline void integrator_state_copy_only(const IntegratorState to_state,
- const IntegratorState 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, array_size) \
- ++index; \
- } \
- while (index < array_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
-}
-
-ccl_device_inline void integrator_state_move(const IntegratorState to_state,
- const IntegratorState state)
-{
- integrator_state_copy_only(to_state, state);
-
- INTEGRATOR_STATE_WRITE(path, queued_kernel) = 0;
- INTEGRATOR_STATE_WRITE(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(INTEGRATOR_STATE_ARGS)
-{
-#if defined(__KERNEL_GPU__)
- const IntegratorState to_state = atomic_fetch_and_add_uint32(
- &kernel_integrator_state.next_shadow_catcher_path_index[0], 1);
-
- integrator_state_copy_only(to_state, state);
-
- kernel_integrator_state.path.flag[to_state] |= PATH_RAY_SHADOW_CATCHER_PASS;
-
- /* Sanity check: expect to split in the intersect-closest kernel, where there is no shadow ray
- * and no sorting yet. */
- kernel_assert(INTEGRATOR_STATE(shadow_path, queued_kernel) == 0);
- kernel_assert(kernel_integrator_state.sort_key_counter[INTEGRATOR_STATE(path, queued_kernel)] ==
- nullptr);
-#else
-
- IntegratorStateCPU *ccl_restrict split_state = state + 1;
-
- *split_state = *state;
-
- split_state->path.flag |= PATH_RAY_SHADOW_CATCHER_PASS;
-#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 9490738404e..00000000000
--- a/intern/cycles/kernel/integrator/integrator_subsurface.h
+++ /dev/null
@@ -1,623 +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"
-
-CCL_NAMESPACE_BEGIN
-
-#ifdef __SUBSURFACE__
-
-ccl_device int subsurface_bounce(INTEGRATOR_STATE_ARGS, ShaderData *sd, 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(path, flag) & PATH_RAY_DIFFUSE_ANCESTOR));
-
- /* Setup path state for intersect_subsurface kernel. */
- const Bssrdf *bssrdf = (const Bssrdf *)sc;
-
- /* Setup ray into surface. */
- INTEGRATOR_STATE_WRITE(ray, P) = sd->P;
- INTEGRATOR_STATE_WRITE(ray, D) = sd->N;
- INTEGRATOR_STATE_WRITE(ray, t) = FLT_MAX;
- INTEGRATOR_STATE_WRITE(ray, dP) = differential_make_compact(sd->dP);
- INTEGRATOR_STATE_WRITE(ray, dD) = differential_zero_compact();
-
- /* Pass along object info, reusing isect to save memory. */
- INTEGRATOR_STATE_WRITE(isect, Ng) = sd->Ng;
- INTEGRATOR_STATE_WRITE(isect, object) = sd->object;
-
- /* Pass BSSRDF parameters. */
- const uint32_t path_flag = INTEGRATOR_STATE_WRITE(path, flag);
- INTEGRATOR_STATE_WRITE(path, flag) = (path_flag & ~PATH_RAY_CAMERA) | PATH_RAY_SUBSURFACE;
- INTEGRATOR_STATE_WRITE(path, throughput) *= shader_bssrdf_sample_weight(sd, sc);
-
- if (kernel_data.kernel_features & KERNEL_FEATURE_LIGHT_PASSES) {
- if (INTEGRATOR_STATE(path, bounce) == 0) {
- INTEGRATOR_STATE_WRITE(path, diffuse_glossy_ratio) = one_float3();
- }
- }
-
- INTEGRATOR_STATE_WRITE(subsurface, albedo) = bssrdf->albedo;
- INTEGRATOR_STATE_WRITE(subsurface, radius) = bssrdf->radius;
- INTEGRATOR_STATE_WRITE(subsurface, roughness) = bssrdf->roughness;
- INTEGRATOR_STATE_WRITE(subsurface, anisotropy) = bssrdf->anisotropy;
-
- return LABEL_SUBSURFACE_SCATTER;
-}
-
-ccl_device void subsurface_shader_data_setup(INTEGRATOR_STATE_ARGS, ShaderData *sd)
-{
- /* 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();
- const float roughness = INTEGRATOR_STATE(subsurface, roughness);
-
-# ifdef __PRINCIPLED__
- if (roughness != FLT_MAX) {
- PrincipledDiffuseBsdf *bsdf = (PrincipledDiffuseBsdf *)bsdf_alloc(
- sd, sizeof(PrincipledDiffuseBsdf), weight);
-
- if (bsdf) {
- bsdf->N = N;
- bsdf->roughness = roughness;
- sd->flag |= bsdf_principled_diffuse_setup(bsdf);
-
- /* replace CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID with this special ID so render passes
- * can recognize it as not being a regular Disney principled diffuse closure */
- bsdf->type = CLOSURE_BSDF_BSSRDF_PRINCIPLED_ID;
- }
- }
- else
-# endif /* __PRINCIPLED__ */
- {
- DiffuseBsdf *bsdf = (DiffuseBsdf *)bsdf_alloc(sd, sizeof(DiffuseBsdf), weight);
-
- if (bsdf) {
- bsdf->N = N;
- sd->flag |= bsdf_diffuse_setup(bsdf);
-
- /* replace CLOSURE_BSDF_DIFFUSE_ID with this special ID so render passes
- * can recognize it as not being a regular diffuse closure */
- bsdf->type = CLOSURE_BSDF_BSSRDF_ID;
- }
- }
-}
-
-/* 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, float *sigma_t, 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,
- float3 *sigma_t,
- float3 *alpha,
- 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,
- 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(INTEGRATOR_STATE_ARGS,
- RNGState rng_state,
- Ray &ray,
- 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(ray, P);
- const float3 N = INTEGRATOR_STATE(ray, D);
- const float ray_dP = INTEGRATOR_STATE(ray, dP);
- const float time = INTEGRATOR_STATE(ray, time);
- const float3 Ng = INTEGRATOR_STATE(isect, Ng);
- const int object = INTEGRATOR_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(subsurface, albedo);
- const float3 radius = INTEGRATOR_STATE(subsurface, radius);
- const float anisotropy = INTEGRATOR_STATE(subsurface, anisotropy);
-
- float3 sigma_t, alpha;
- float3 throughput = INTEGRATOR_STATE_WRITE(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 raycast 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 raycast 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(path, throughput) = throughput;
- }
-
- return hit;
-}
-
-ccl_device_inline bool subsurface_scatter(INTEGRATOR_STATE_ARGS)
-{
- RNGState rng_state;
- path_state_rng_load(INTEGRATOR_STATE_PASS, &rng_state);
-
- Ray ray ccl_optional_struct_init;
- LocalIntersection ss_isect ccl_optional_struct_init;
-
- if (!subsurface_random_walk(INTEGRATOR_STATE_PASS, rng_state, ray, ss_isect)) {
- return false;
- }
-
-# ifdef __VOLUME__
- /* Update volume stack if needed. */
- if (kernel_data.integrator.use_volumes) {
- const int object = intersection_get_object(kg, &ss_isect.hits[0]);
- const int object_flag = kernel_tex_fetch(__object_flag, object);
-
- if (object_flag & SD_OBJECT_INTERSECTS_VOLUME) {
- float3 P = INTEGRATOR_STATE(ray, P);
- const float3 Ng = INTEGRATOR_STATE(isect, Ng);
- const float3 offset_P = ray_offset(P, -Ng);
-
- integrator_volume_stack_update_for_subsurface(INTEGRATOR_STATE_PASS, 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(INTEGRATOR_STATE_PASS, &ss_isect.hits[0]);
- integrator_state_write_ray(INTEGRATOR_STATE_PASS, &ray);
-
- /* Advanced random number offset for bounce. */
- INTEGRATOR_STATE_WRITE(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) || (kernel_data.film.pass_ao != PASS_UNUSED)) {
- 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_volume_stack.h b/intern/cycles/kernel/integrator/integrator_volume_stack.h
deleted file mode 100644
index d53070095f0..00000000000
--- a/intern/cycles/kernel/integrator/integrator_volume_stack.h
+++ /dev/null
@@ -1,223 +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
-
-CCL_NAMESPACE_BEGIN
-
-/* Volume Stack
- *
- * This is an array of object/shared ID's that the current segment of the path
- * is inside of. */
-
-template<typename StackReadOp, typename StackWriteOp>
-ccl_device void volume_stack_enter_exit(INTEGRATOR_STATE_ARGS,
- const ShaderData *sd,
- StackReadOp stack_read,
- StackWriteOp stack_write)
-{
- /* todo: we should have some way for objects to indicate if they want the
- * world shader to work inside them. excluding it by default is problematic
- * because non-volume objects can't be assumed to be closed manifolds */
- if (!(sd->flag & SD_HAS_VOLUME)) {
- return;
- }
-
- if (sd->flag & SD_BACKFACING) {
- /* Exit volume object: remove from stack. */
- for (int i = 0;; i++) {
- VolumeStack entry = stack_read(i);
- if (entry.shader == SHADER_NONE) {
- break;
- }
-
- if (entry.object == sd->object) {
- /* Shift back next stack entries. */
- do {
- entry = stack_read(i + 1);
- stack_write(i, entry);
- i++;
- } while (entry.shader != SHADER_NONE);
-
- return;
- }
- }
- }
- else {
- /* Enter volume object: add to stack. */
- int i;
- for (i = 0;; i++) {
- VolumeStack entry = stack_read(i);
- if (entry.shader == SHADER_NONE) {
- break;
- }
-
- /* Already in the stack? then we have nothing to do. */
- if (entry.object == sd->object) {
- return;
- }
- }
-
- /* If we exceed the stack limit, ignore. */
- if (i >= VOLUME_STACK_SIZE - 1) {
- return;
- }
-
- /* Add to the end of the stack. */
- const VolumeStack new_entry = {sd->object, sd->shader};
- const VolumeStack empty_entry = {OBJECT_NONE, SHADER_NONE};
- stack_write(i, new_entry);
- stack_write(i + 1, empty_entry);
- }
-}
-
-ccl_device void volume_stack_enter_exit(INTEGRATOR_STATE_ARGS, const ShaderData *sd)
-{
- volume_stack_enter_exit(
- INTEGRATOR_STATE_PASS,
- sd,
- [=](const int i) { return integrator_state_read_volume_stack(INTEGRATOR_STATE_PASS, i); },
- [=](const int i, const VolumeStack entry) {
- integrator_state_write_volume_stack(INTEGRATOR_STATE_PASS, i, entry);
- });
-}
-
-ccl_device void shadow_volume_stack_enter_exit(INTEGRATOR_STATE_ARGS, const ShaderData *sd)
-{
- volume_stack_enter_exit(
- INTEGRATOR_STATE_PASS,
- sd,
- [=](const int i) {
- return integrator_state_read_shadow_volume_stack(INTEGRATOR_STATE_PASS, i);
- },
- [=](const int i, const VolumeStack entry) {
- integrator_state_write_shadow_volume_stack(INTEGRATOR_STATE_PASS, i, entry);
- });
-}
-
-/* Clean stack after the last bounce.
- *
- * It is expected that all volumes are closed manifolds, so at the time when ray
- * hits nothing (for example, it is a last bounce which goes to environment) the
- * only expected volume in the stack is the world's one. All the rest volume
- * entries should have been exited already.
- *
- * This isn't always true because of ray intersection precision issues, which
- * could lead us to an infinite non-world volume in the stack, causing render
- * artifacts.
- *
- * Use this function after the last bounce to get rid of all volumes apart from
- * the world's one after the last bounce to avoid render artifacts.
- */
-ccl_device_inline void volume_stack_clean(INTEGRATOR_STATE_ARGS)
-{
- if (kernel_data.background.volume_shader != SHADER_NONE) {
- /* Keep the world's volume in stack. */
- INTEGRATOR_STATE_ARRAY_WRITE(volume_stack, 1, shader) = SHADER_NONE;
- }
- else {
- INTEGRATOR_STATE_ARRAY_WRITE(volume_stack, 0, shader) = SHADER_NONE;
- }
-}
-
-template<typename StackReadOp>
-ccl_device float volume_stack_step_size(INTEGRATOR_STATE_ARGS, StackReadOp stack_read)
-{
- float step_size = FLT_MAX;
-
- for (int i = 0;; i++) {
- VolumeStack entry = stack_read(i);
- if (entry.shader == SHADER_NONE) {
- break;
- }
-
- int shader_flag = kernel_tex_fetch(__shaders, (entry.shader & SHADER_MASK)).flags;
-
- bool heterogeneous = false;
-
- if (shader_flag & SD_HETEROGENEOUS_VOLUME) {
- heterogeneous = true;
- }
- else if (shader_flag & SD_NEED_VOLUME_ATTRIBUTES) {
- /* We want to render world or objects without any volume grids
- * as homogeneous, but can only verify this at run-time since other
- * heterogeneous volume objects may be using the same shader. */
- int object = entry.object;
- if (object != OBJECT_NONE) {
- int object_flag = kernel_tex_fetch(__object_flag, object);
- if (object_flag & SD_OBJECT_HAS_VOLUME_ATTRIBUTES) {
- heterogeneous = true;
- }
- }
- }
-
- if (heterogeneous) {
- float object_step_size = object_volume_step_size(kg, entry.object);
- object_step_size *= kernel_data.integrator.volume_step_rate;
- step_size = fminf(object_step_size, step_size);
- }
- }
-
- return step_size;
-}
-
-typedef enum VolumeSampleMethod {
- VOLUME_SAMPLE_NONE = 0,
- VOLUME_SAMPLE_DISTANCE = (1 << 0),
- VOLUME_SAMPLE_EQUIANGULAR = (1 << 1),
- VOLUME_SAMPLE_MIS = (VOLUME_SAMPLE_DISTANCE | VOLUME_SAMPLE_EQUIANGULAR),
-} VolumeSampleMethod;
-
-ccl_device VolumeSampleMethod volume_stack_sample_method(INTEGRATOR_STATE_ARGS)
-{
- VolumeSampleMethod method = VOLUME_SAMPLE_NONE;
-
- for (int i = 0;; i++) {
- VolumeStack entry = integrator_state_read_volume_stack(INTEGRATOR_STATE_PASS, i);
- if (entry.shader == SHADER_NONE) {
- break;
- }
-
- int shader_flag = kernel_tex_fetch(__shaders, (entry.shader & SHADER_MASK)).flags;
-
- if (shader_flag & SD_VOLUME_MIS) {
- /* Multiple importance sampling. */
- return VOLUME_SAMPLE_MIS;
- }
- else if (shader_flag & SD_VOLUME_EQUIANGULAR) {
- /* Distance + equiangular sampling -> multiple importance sampling. */
- if (method == VOLUME_SAMPLE_DISTANCE) {
- return VOLUME_SAMPLE_MIS;
- }
-
- /* Only equiangular sampling. */
- method = VOLUME_SAMPLE_EQUIANGULAR;
- }
- else {
- /* Distance + equiangular sampling -> multiple importance sampling. */
- if (method == VOLUME_SAMPLE_EQUIANGULAR) {
- return VOLUME_SAMPLE_MIS;
- }
-
- /* Distance sampling only. */
- method = VOLUME_SAMPLE_DISTANCE;
- }
- }
-
- return method;
-}
-
-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..4c5265189fa
--- /dev/null
+++ b/intern/cycles/kernel/integrator/intersect_closest.h
@@ -0,0 +1,363 @@
+/*
+ * 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
+
+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);
+ INTEGRATOR_STATE_WRITE(state, path, continuation_probability) = probability;
+
+ 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;
+}
+
+#ifdef __SHADOW_CATCHER__
+/* Split path if a shadow catcher was hit. */
+ccl_device_forceinline void integrator_split_shadow_catcher(
+ KernelGlobals kg,
+ IntegratorState state,
+ ccl_private const Intersection *ccl_restrict isect,
+ ccl_global float *ccl_restrict render_buffer)
+{
+ /* Test if we hit a shadow catcher object, and potentially split the path to continue tracing two
+ * paths from here. */
+ const int object_flags = intersection_get_object_flags(kg, isect);
+ if (!kernel_shadow_catcher_is_path_split_bounce(kg, state, object_flags)) {
+ return;
+ }
+
+ kernel_write_shadow_catcher_bounce_data(kg, state, render_buffer);
+
+ /* Mark state as having done a shadow catcher split 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;
+
+ /* Copy current state to new state. */
+ state = integrator_state_shadow_catcher_split(kg, state);
+
+ /* Initialize new state.
+ *
+ * Note that the splitting leaves kernel and sorting counters as-is, so use INIT semantic for
+ * the matte path. */
+
+ /* Mark current state so that it will only track contribution of shadow catcher objects ignoring
+ * non-catcher objects. */
+ INTEGRATOR_STATE_WRITE(state, path, flag) |= PATH_RAY_SHADOW_CATCHER_PASS;
+
+ if (kernel_data.film.pass_background != PASS_UNUSED && !kernel_data.background.transparent) {
+ /* If using background pass, schedule background shading kernel so that we have a background
+ * to alpha-over on. The background kernel will then continue the path afterwards. */
+ INTEGRATOR_STATE_WRITE(state, path, flag) |= PATH_RAY_SHADOW_CATCHER_BACKGROUND;
+ INTEGRATOR_PATH_INIT(DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND);
+ return;
+ }
+
+ if (!integrator_state_volume_stack_is_empty(kg, state)) {
+ /* Volume stack is not empty. Re-init the volume stack to exclude any non-shadow catcher
+ * objects from it, and then continue shading volume and shadow catcher surface after. */
+ INTEGRATOR_PATH_INIT(DEVICE_KERNEL_INTEGRATOR_INTERSECT_VOLUME_STACK);
+ return;
+ }
+
+ /* Continue with shading shadow catcher surface. */
+ const int shader = intersection_get_shader(kg, isect);
+ const int flags = kernel_tex_fetch(__shaders, shader).flags;
+ const bool use_raytrace_kernel = (flags & SD_HAS_RAYTRACE);
+
+ 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);
+ }
+}
+
+/* Schedule next kernel to be executed after updating volume stack for shadow catcher. */
+template<uint32_t current_kernel>
+ccl_device_forceinline void integrator_intersect_next_kernel_after_shadow_catcher_volume(
+ KernelGlobals kg, IntegratorState state)
+{
+ /* Continue with shading shadow catcher surface. Same as integrator_split_shadow_catcher, but
+ * using NEXT instead of INIT. */
+ Intersection isect ccl_optional_struct_init;
+ integrator_state_read_isect(kg, state, &isect);
+
+ const int shader = intersection_get_shader(kg, &isect);
+ const int flags = kernel_tex_fetch(__shaders, shader).flags;
+ const bool use_raytrace_kernel = (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);
+ }
+}
+
+/* Schedule next kernel to be executed after executing background shader for shadow catcher. */
+template<uint32_t current_kernel>
+ccl_device_forceinline void integrator_intersect_next_kernel_after_shadow_catcher_background(
+ KernelGlobals kg, IntegratorState state)
+{
+ /* Same logic as integrator_split_shadow_catcher, but using NEXT instead of INIT. */
+ if (!integrator_state_volume_stack_is_empty(kg, state)) {
+ /* Volume stack is not empty. Re-init the volume stack to exclude any non-shadow catcher
+ * objects from it, and then continue shading volume and shadow catcher surface after. */
+ INTEGRATOR_PATH_NEXT(current_kernel, DEVICE_KERNEL_INTEGRATOR_INTERSECT_VOLUME_STACK);
+ return;
+ }
+
+ /* Continue with shading shadow catcher surface. */
+ integrator_intersect_next_kernel_after_shadow_catcher_volume<current_kernel>(kg, state);
+}
+#endif
+
+/* Schedule next kernel to be executed after intersect closest.
+ *
+ * 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_next_kernel(
+ KernelGlobals kg,
+ IntegratorState state,
+ ccl_private const Intersection *ccl_restrict isect,
+ ccl_global float *ccl_restrict render_buffer,
+ const bool hit)
+{
+ /* Continue with volume kernel if we are inside a volume, regardless if we hit anything. */
+#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(kg, state, flags)) {
+ INTEGRATOR_PATH_NEXT(current_kernel, DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME);
+ }
+ else {
+ INTEGRATOR_PATH_TERMINATE(current_kernel);
+ }
+ return;
+ }
+#endif
+
+ if (hit) {
+ /* Hit a surface, continue with light or surface kernel. */
+ if (isect->type & PRIMITIVE_LAMP) {
+ INTEGRATOR_PATH_NEXT(current_kernel, DEVICE_KERNEL_INTEGRATOR_SHADE_LIGHT);
+ }
+ 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(kg, state, flags)) {
+ const bool use_raytrace_kernel = (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__
+ /* Handle shadow catcher. */
+ integrator_split_shadow_catcher(kg, state, isect, render_buffer);
+#endif
+ }
+ else {
+ INTEGRATOR_PATH_TERMINATE(current_kernel);
+ }
+ }
+ }
+ else {
+ /* Nothing hit, continue with background kernel. */
+ INTEGRATOR_PATH_NEXT(current_kernel, DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND);
+ }
+}
+
+/* Schedule next kernel to be executed after shade volume.
+ *
+ * The logic here matches integrator_intersect_next_kernel, except that
+ * volume shading and termination testing have already been done. */
+template<uint32_t current_kernel>
+ccl_device_forceinline void integrator_intersect_next_kernel_after_volume(
+ KernelGlobals kg,
+ IntegratorState state,
+ ccl_private const Intersection *ccl_restrict isect,
+ ccl_global float *ccl_restrict render_buffer)
+{
+ if (isect->prim != PRIM_NONE) {
+ /* Hit a surface, continue with light or surface kernel. */
+ if (isect->type & PRIMITIVE_LAMP) {
+ INTEGRATOR_PATH_NEXT(current_kernel, 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;
+ const bool use_raytrace_kernel = (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__
+ /* Handle shadow catcher. */
+ integrator_split_shadow_catcher(kg, state, isect, render_buffer);
+#endif
+ return;
+ }
+ }
+ else {
+ /* Nothing hit, continue with background kernel. */
+ INTEGRATOR_PATH_NEXT(current_kernel, DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND);
+ return;
+ }
+}
+
+ccl_device void integrator_intersect_closest(KernelGlobals kg,
+ IntegratorState state,
+ ccl_global float *ccl_restrict render_buffer)
+{
+ 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;
+ isect.object = OBJECT_NONE;
+ isect.prim = PRIM_NONE;
+ ray.self.object = last_isect_object;
+ ray.self.prim = last_isect_prim;
+ ray.self.light_object = OBJECT_NONE;
+ ray.self.light_prim = PRIM_NONE;
+ 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, state, &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);
+
+ /* Setup up next kernel to be executed. */
+ integrator_intersect_next_kernel<DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST>(
+ kg, state, &isect, render_buffer, hit);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/integrator/intersect_shadow.h b/intern/cycles/kernel/integrator/intersect_shadow.h
new file mode 100644
index 00000000000..1ba8724826b
--- /dev/null
+++ b/intern/cycles/kernel/integrator/intersect_shadow.h
@@ -0,0 +1,193 @@
+/*
+ * 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
+
+CCL_NAMESPACE_BEGIN
+
+/* Visibility for the shadow ray. */
+ccl_device_forceinline uint integrate_intersect_shadow_visibility(KernelGlobals kg,
+ ConstIntegratorShadowState state)
+{
+ uint visibility = PATH_RAY_SHADOW;
+
+#ifdef __SHADOW_CATCHER__
+ const uint32_t path_flag = INTEGRATOR_STATE(state, shadow_path, flag);
+ visibility = SHADOW_CATCHER_PATH_VISIBILITY(path_flag, visibility);
+#endif
+
+ return visibility;
+}
+
+ccl_device bool integrate_intersect_shadow_opaque(KernelGlobals kg,
+ IntegratorShadowState state,
+ ccl_private const Ray *ray,
+ const uint visibility)
+{
+ /* Mask which will pick only opaque visibility bits from the `visibility`.
+ * Calculate the mask at compile time: the visibility will either be a high bits for the shadow
+ * catcher objects, or lower bits for the regular objects (there is no need to check the path
+ * state here again). */
+ constexpr const uint opaque_mask = SHADOW_CATCHER_VISIBILITY_SHIFT(PATH_RAY_SHADOW_OPAQUE) |
+ PATH_RAY_SHADOW_OPAQUE;
+
+ Intersection isect;
+ const bool opaque_hit = scene_intersect(kg, ray, visibility & opaque_mask, &isect);
+
+ if (!opaque_hit) {
+ INTEGRATOR_STATE_WRITE(state, shadow_path, num_hits) = 0;
+ }
+
+ return opaque_hit;
+}
+
+ccl_device_forceinline int integrate_shadow_max_transparent_hits(KernelGlobals kg,
+ ConstIntegratorShadowState state)
+{
+ const int transparent_max_bounce = kernel_data.integrator.transparent_max_bounce;
+ const int transparent_bounce = INTEGRATOR_STATE(state, shadow_path, transparent_bounce);
+
+ return max(transparent_max_bounce - transparent_bounce - 1, 0);
+}
+
+#ifdef __TRANSPARENT_SHADOWS__
+# if defined(__KERNEL_CPU__)
+ccl_device int shadow_intersections_compare(const void *a, const void *b)
+{
+ const Intersection *isect_a = (const Intersection *)a;
+ const Intersection *isect_b = (const Intersection *)b;
+
+ if (isect_a->t < isect_b->t)
+ return -1;
+ else if (isect_a->t > isect_b->t)
+ return 1;
+ else
+ return 0;
+}
+# endif
+
+ccl_device_inline void sort_shadow_intersections(IntegratorShadowState state, uint num_hits)
+{
+ kernel_assert(num_hits > 0);
+
+# ifdef __KERNEL_GPU__
+ /* Use bubble sort which has more friendly memory pattern on GPU. */
+ bool swapped;
+ do {
+ swapped = false;
+ for (int j = 0; j < num_hits - 1; ++j) {
+ if (INTEGRATOR_STATE_ARRAY(state, shadow_isect, j, t) >
+ INTEGRATOR_STATE_ARRAY(state, shadow_isect, j + 1, t)) {
+ struct Intersection tmp_j ccl_optional_struct_init;
+ struct Intersection tmp_j_1 ccl_optional_struct_init;
+ integrator_state_read_shadow_isect(state, &tmp_j, j);
+ integrator_state_read_shadow_isect(state, &tmp_j_1, j + 1);
+ integrator_state_write_shadow_isect(state, &tmp_j_1, j);
+ integrator_state_write_shadow_isect(state, &tmp_j, j + 1);
+ swapped = true;
+ }
+ }
+ --num_hits;
+ } while (swapped);
+# else
+ Intersection *isect_array = (Intersection *)state->shadow_isect;
+ qsort(isect_array, num_hits, sizeof(Intersection), shadow_intersections_compare);
+# endif
+}
+
+ccl_device bool integrate_intersect_shadow_transparent(KernelGlobals kg,
+ IntegratorShadowState state,
+ ccl_private const Ray *ray,
+ const uint visibility)
+{
+ /* Limit the number hits to the max transparent bounces allowed and the size that we
+ * have available in the integrator state. */
+ const uint max_hits = integrate_shadow_max_transparent_hits(kg, state);
+ uint num_hits = 0;
+ float throughput = 1.0f;
+ bool opaque_hit = scene_intersect_shadow_all(
+ kg, state, ray, visibility, max_hits, &num_hits, &throughput);
+
+ /* Computed throughput from baked shadow transparency, where we can bypass recording
+ * intersections and shader evaluation. */
+ if (throughput != 1.0f) {
+ INTEGRATOR_STATE_WRITE(state, shadow_path, throughput) *= throughput;
+ }
+
+ /* If number of hits exceed the transparent bounces limit, make opaque. */
+ if (num_hits > max_hits) {
+ opaque_hit = true;
+ }
+
+ if (!opaque_hit) {
+ const uint num_recorded_hits = min(num_hits, min(max_hits, INTEGRATOR_SHADOW_ISECT_SIZE));
+
+ if (num_recorded_hits > 0) {
+ sort_shadow_intersections(state, num_recorded_hits);
+ }
+
+ INTEGRATOR_STATE_WRITE(state, shadow_path, num_hits) = num_hits;
+ }
+ else {
+ INTEGRATOR_STATE_WRITE(state, shadow_path, num_hits) = 0;
+ }
+
+ return opaque_hit;
+}
+#endif
+
+ccl_device void integrator_intersect_shadow(KernelGlobals kg, IntegratorShadowState state)
+{
+ PROFILING_INIT(kg, PROFILING_INTERSECT_SHADOW);
+
+ /* Read ray from integrator state into local memory. */
+ Ray ray ccl_optional_struct_init;
+ integrator_state_read_shadow_ray(kg, state, &ray);
+ ray.self.object = INTEGRATOR_STATE_ARRAY(state, shadow_isect, 0, object);
+ ray.self.prim = INTEGRATOR_STATE_ARRAY(state, shadow_isect, 0, prim);
+ ray.self.light_object = INTEGRATOR_STATE_ARRAY(state, shadow_isect, 1, object);
+ ray.self.light_prim = INTEGRATOR_STATE_ARRAY(state, shadow_isect, 1, prim);
+ /* Compute visibility. */
+ const uint visibility = integrate_intersect_shadow_visibility(kg, state);
+
+#ifdef __TRANSPARENT_SHADOWS__
+ /* TODO: compile different kernels depending on this? Especially for OptiX
+ * conditional trace calls are bad. */
+ const bool opaque_hit = (kernel_data.integrator.transparent_shadows) ?
+ integrate_intersect_shadow_transparent(kg, state, &ray, visibility) :
+ integrate_intersect_shadow_opaque(kg, state, &ray, visibility);
+#else
+ const bool opaque_hit = integrate_intersect_shadow_opaque(kg, state, &ray, visibility);
+#endif
+
+ if (opaque_hit) {
+ /* Hit an opaque surface, shadow path ends here. */
+ INTEGRATOR_SHADOW_PATH_TERMINATE(DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW);
+ return;
+ }
+ else {
+ /* Hit nothing or transparent surfaces, continue to shadow kernel
+ * for shading and render buffer output.
+ *
+ * TODO: could also write to render buffer directly if no transparent shadows?
+ * Could save a kernel execution for the common case. */
+ INTEGRATOR_SHADOW_PATH_NEXT(DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW,
+ DEVICE_KERNEL_INTEGRATOR_SHADE_SHADOW);
+ return;
+ }
+}
+
+CCL_NAMESPACE_END
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..ee3d82ebacb
--- /dev/null
+++ b/intern/cycles/kernel/integrator/intersect_volume_stack.h
@@ -0,0 +1,239 @@
+/*
+ * 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);
+ volume_ray.self.object = INTEGRATOR_STATE(state, isect, object);
+ volume_ray.self.prim = INTEGRATOR_STATE(state, isect, prim);
+ volume_ray.self.light_object = OBJECT_NONE;
+ volume_ray.self.light_prim = PRIM_NONE;
+ /* Store to avoid global fetches on every intersection step. */
+ const uint volume_stack_size = kernel_data.volume_stack_size;
+
+ const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
+ const uint32_t visibility = SHADOW_CATCHER_PATH_VISIBILITY(path_flag, PATH_RAY_ALL_VISIBILITY);
+
+#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) {
+ 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, 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 = stack_sd->P;
+ 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_volume_stack_init(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);
+
+ /* Trace ray in random direction. Any direction works, Z up is a guess to get the
+ * fewest hits. */
+ volume_ray.D = make_float3(0.0f, 0.0f, 1.0f);
+ volume_ray.t = FLT_MAX;
+ volume_ray.self.object = OBJECT_NONE;
+ volume_ray.self.prim = PRIM_NONE;
+ volume_ray.self.light_object = OBJECT_NONE;
+ volume_ray.self.light_prim = PRIM_NONE;
+
+ int stack_index = 0, enclosed_index = 0;
+
+ const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
+ const uint32_t visibility = SHADOW_CATCHER_PATH_VISIBILITY(path_flag, PATH_RAY_CAMERA);
+
+ /* Initialize volume stack with background volume For shadow catcher the
+ * background volume is always assumed to be CG. */
+ if (kernel_data.background.volume_shader != SHADER_NONE) {
+ if (!(path_flag & PATH_RAY_SHADOW_CATCHER_PASS)) {
+ INTEGRATOR_STATE_ARRAY_WRITE(state, volume_stack, stack_index, object) = OBJECT_NONE;
+ INTEGRATOR_STATE_ARRAY_WRITE(
+ state, volume_stack, stack_index, shader) = kernel_data.background.volume_shader;
+ 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 < MAX_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 = stack_sd->P;
+ ++step;
+ }
+#endif
+
+ /* Write terminator. */
+ const VolumeStack new_entry = {OBJECT_NONE, SHADER_NONE};
+ integrator_state_write_volume_stack(state, stack_index, new_entry);
+}
+
+ccl_device void integrator_intersect_volume_stack(KernelGlobals kg, IntegratorState state)
+{
+ integrator_volume_stack_init(kg, state);
+
+ if (INTEGRATOR_STATE(state, path, flag) & PATH_RAY_SHADOW_CATCHER_PASS) {
+ /* Volume stack re-init for shadow catcher, continue with shading of hit. */
+ integrator_intersect_next_kernel_after_shadow_catcher_volume<
+ DEVICE_KERNEL_INTEGRATOR_INTERSECT_VOLUME_STACK>(kg, state);
+ }
+ else {
+ /* Volume stack init for camera rays, continue with intersection of camera ray. */
+ 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..43313400a11
--- /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, render_buffer);
+ 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..ff6b55a73c3
--- /dev/null
+++ b/intern/cycles/kernel/integrator/path_state.h
@@ -0,0 +1,378 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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, continuation_probability) = 1.0f;
+ INTEGRATOR_STATE_WRITE(state, path, throughput) = make_float3(1.0f, 1.0f, 1.0f);
+
+ INTEGRATOR_STATE_WRITE(state, isect, object) = OBJECT_NONE;
+ INTEGRATOR_STATE_WRITE(state, isect, prim) = PRIM_NONE;
+
+ 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 (!(flag & PATH_RAY_ANY_PASS)) {
+ 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 (!(flag & PATH_RAY_ANY_PASS) && !(flag & PATH_RAY_TRANSPARENT_BACKGROUND)) {
+ flag |= PATH_RAY_SURFACE_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. */
+ 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..a8ebbe908ae
--- /dev/null
+++ b/intern/cycles/kernel/integrator/shade_background.h
@@ -0,0 +1,205 @@
+/*
+ * 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 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 = light_sample_mis_weight_forward(kg, 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 = light_sample_mis_weight_forward(kg, 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) {
+ /* Special case for shadow catcher where we want to fill the background pass
+ * behind the shadow catcher but also continue tracing the path. */
+ INTEGRATOR_STATE_WRITE(state, path, flag) &= ~PATH_RAY_SHADOW_CATCHER_BACKGROUND;
+ integrator_intersect_next_kernel_after_shadow_catcher_background<
+ DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND>(kg, state);
+ 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..0a82c9cadef
--- /dev/null
+++ b/intern/cycles/kernel/integrator/shade_light.h
@@ -0,0 +1,129 @@
+/*
+ * 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? Ray should not intersect surface anymore as the
+ * object and prim ids will prevent self intersection. */
+ const float3 new_ray_P = ray_P + ray_D * isect.t;
+ 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) = 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 = light_sample_mis_weight_forward(kg, 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..3e8eba29ef7
--- /dev/null
+++ b/intern/cycles/kernel/integrator/shade_shadow.h
@@ -0,0 +1,192 @@
+/*
+ * 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);
+ ray.self.object = OBJECT_NONE;
+ ray.self.prim = PRIM_NONE;
+ ray.self.light_object = OBJECT_NONE;
+ ray.self.light_prim = PRIM_NONE;
+ /* 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);
+
+ VOLUME_READ_LAMBDA(integrator_state_read_shadow_volume_stack(state, i));
+ const float step_size = volume_stack_step_size(kg, volume_read_lambda_pass);
+
+ 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_P + last_hit_t * 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..329380fc464
--- /dev/null
+++ b/intern/cycles/kernel/integrator/shade_surface.h
@@ -0,0 +1,568 @@
+/*
+ * 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"
+
+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_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 = light_sample_mis_weight_forward(kg, 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 = light_sample_mis_weight_nee(kg, 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);
+ // Save memory by storing the light and object indices in the shadow_isect
+ INTEGRATOR_STATE_ARRAY_WRITE(shadow_state, shadow_isect, 0, object) = ray.self.object;
+ INTEGRATOR_STATE_ARRAY_WRITE(shadow_state, shadow_isect, 0, prim) = ray.self.prim;
+ INTEGRATOR_STATE_ARRAY_WRITE(shadow_state, shadow_isect, 1, object) = ray.self.light_object;
+ INTEGRATOR_STATE_ARRAY_WRITE(shadow_state, shadow_isect, 1, prim) = ray.self.light_prim;
+
+ /* 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 |= (shadow_flag & PATH_RAY_ANY_PASS) ? 0 : PATH_RAY_SURFACE_PASS;
+ const float3 throughput = INTEGRATOR_STATE(state, path, throughput) * bsdf_eval_sum(&bsdf_eval);
+
+ if (kernel_data.kernel_features & KERNEL_FEATURE_LIGHT_PASSES) {
+ const packed_float3 pass_diffuse_weight =
+ (bounce == 0) ? packed_float3(bsdf_eval_pass_diffuse_weight(&bsdf_eval)) :
+ INTEGRATOR_STATE(state, path, pass_diffuse_weight);
+ const packed_float3 pass_glossy_weight = (bounce == 0) ?
+ packed_float3(
+ bsdf_eval_pass_glossy_weight(&bsdf_eval)) :
+ INTEGRATOR_STATE(state, path, pass_glossy_weight);
+ INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, pass_diffuse_weight) = pass_diffuse_weight;
+ INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, pass_glossy_weight) = pass_glossy_weight;
+ }
+
+ 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) = sd->P;
+ 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, pass_diffuse_weight) = bsdf_eval_pass_diffuse_weight(
+ &bsdf_eval);
+ INTEGRATOR_STATE_WRITE(state, path, pass_glossy_weight) = bsdf_eval_pass_glossy_weight(
+ &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) = sd->P;
+
+ /* 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 = sd->P;
+ ray.D = ao_D;
+ ray.t = kernel_data.integrator.ao_bounces_distance;
+ ray.time = sd->time;
+ ray.self.object = sd->object;
+ ray.self.prim = sd->prim;
+ ray.self.light_object = OBJECT_NONE;
+ ray.self.light_prim = PRIM_NONE;
+ 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);
+ INTEGRATOR_STATE_ARRAY_WRITE(shadow_state, shadow_isect, 0, object) = ray.self.object;
+ INTEGRATOR_STATE_ARRAY_WRITE(shadow_state, shadow_isect, 0, prim) = ray.self.prim;
+ INTEGRATOR_STATE_ARRAY_WRITE(shadow_state, shadow_isect, 1, object) = ray.self.light_object;
+ INTEGRATOR_STATE_ARRAY_WRITE(shadow_state, shadow_isect, 1, prim) = ray.self.light_prim;
+
+ /* 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, path_flag);
+
+#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 :
+ INTEGRATOR_STATE(state, path, continuation_probability);
+ 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
+
+ /* 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..e8d7bfa1374
--- /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"
+
+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)
+{
+ VOLUME_READ_LAMBDA(integrator_state_read_shadow_volume_stack(state, i))
+ shader_eval_volume<true>(kg, state, sd, PATH_RAY_SHADOW, volume_read_lambda_pass);
+
+ 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);
+ VOLUME_READ_LAMBDA(integrator_state_read_volume_stack(state, i))
+ shader_eval_volume<false>(kg, state, sd, path_flag, volume_read_lambda_pass);
+
+ 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" */
+
+/* Below this pdf we ignore samples, as they tend to lead to very long distances.
+ * This can cause performance issues with BVH traversal in OptiX, leading it to
+ * traverse many nodes. Since these contribute very little to the image, just ignore
+ * those samples. */
+# define VOLUME_SAMPLE_PDF_CUTOFF 1e-8f
+
+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 &&
+ vstate.equiangular_pdf > VOLUME_SAMPLE_PDF_CUTOFF) {
+ 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);
+
+ if (vstate.distance_pdf * distance_pdf > VOLUME_SAMPLE_PDF_CUTOFF) {
+ /* 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 += result.indirect_throughput * 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, 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);
+
+ if (!light_distribution_sample_from_volume_segment(
+ kg, light_u, light_v, sd->time, sd->P, bounce, path_flag, ls)) {
+ return false;
+ }
+
+ 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 = light_sample_mis_weight_nee(kg, 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);
+ INTEGRATOR_STATE_ARRAY_WRITE(shadow_state, shadow_isect, 0, object) = ray.self.object;
+ INTEGRATOR_STATE_ARRAY_WRITE(shadow_state, shadow_isect, 0, prim) = ray.self.prim;
+ INTEGRATOR_STATE_ARRAY_WRITE(shadow_state, shadow_isect, 1, object) = ray.self.light_object;
+ INTEGRATOR_STATE_ARRAY_WRITE(shadow_state, shadow_isect, 1, prim) = ray.self.light_prim;
+
+ /* 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 |= (shadow_flag & PATH_RAY_ANY_PASS) ? 0 : PATH_RAY_VOLUME_PASS;
+ const float3 throughput_phase = throughput * bsdf_eval_sum(&phase_eval);
+
+ if (kernel_data.kernel_features & KERNEL_FEATURE_LIGHT_PASSES) {
+ const packed_float3 pass_diffuse_weight = (bounce == 0) ?
+ packed_float3(one_float3()) :
+ INTEGRATOR_STATE(
+ state, path, pass_diffuse_weight);
+ INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, pass_diffuse_weight) = pass_diffuse_weight;
+ INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, pass_glossy_weight) = zero_float3();
+ }
+
+ 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
+ // Save memory by storing last hit prim and object in isect
+ INTEGRATOR_STATE_WRITE(state, isect, prim) = sd->prim;
+ INTEGRATOR_STATE_WRITE(state, isect, object) = sd->object;
+
+ /* 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, pass_diffuse_weight) = one_float3();
+ INTEGRATOR_STATE_WRITE(state, path, pass_glossy_weight) = zero_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. */
+ VOLUME_READ_LAMBDA(integrator_state_read_volume_stack(state, i))
+ const float step_size = volume_stack_step_size(kg, volume_read_lambda_pass);
+
+ /* 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 :
+ INTEGRATOR_STATE(state, path, continuation_probability);
+ 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. */
+ integrator_intersect_next_kernel_after_volume<DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME>(
+ kg, state, &isect, render_buffer);
+ 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..2dcba73561d
--- /dev/null
+++ b/intern/cycles/kernel/integrator/shader_eval.h
@@ -0,0 +1,901 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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,
+ const uint32_t path_flag)
+{
+ /* Filter out closures. */
+ if (kernel_data.integrator.filter_closures) {
+ if (kernel_data.integrator.filter_closures & FILTER_CLOSURE_EMISSION) {
+ sd->closure_emission_background = zero_float3();
+ }
+
+ if (kernel_data.integrator.filter_closures & FILTER_CLOSURE_DIRECT_LIGHT) {
+ sd->flag &= ~SD_BSDF_HAS_EVAL;
+ }
+
+ if (path_flag & PATH_RAY_CAMERA) {
+ for (int i = 0; i < sd->num_closure; i++) {
+ ccl_private ShaderClosure *sc = &sd->closure[i];
+
+ if ((CLOSURE_IS_BSDF_DIFFUSE(sc->type) &&
+ (kernel_data.integrator.filter_closures & FILTER_CLOSURE_DIFFUSE)) ||
+ (CLOSURE_IS_BSDF_GLOSSY(sc->type) &&
+ (kernel_data.integrator.filter_closures & FILTER_CLOSURE_GLOSSY)) ||
+ (CLOSURE_IS_BSDF_TRANSMISSION(sc->type) &&
+ (kernel_data.integrator.filter_closures & FILTER_CLOSURE_TRANSMISSION))) {
+ sc->type = CLOSURE_NONE_ID;
+ sc->sample_weight = 0.0f;
+ }
+ else if ((CLOSURE_IS_BSDF_TRANSPARENT(sc->type) &&
+ (kernel_data.integrator.filter_closures & FILTER_CLOSURE_TRANSPARENT))) {
+ sc->type = CLOSURE_HOLDOUT_ID;
+ sc->sample_weight = 0.0f;
+ sd->flag |= SD_HOLDOUT;
+ }
+ }
+ }
+ }
+
+ /* 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) {
+ bsdf_eval_accum(result_eval, sc->type, eval * sc->weight);
+ 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, CLOSURE_NONE_ID, 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) {
+ bsdf_eval_init(bsdf_eval, sc->type, 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, CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID, eval);
+ 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, CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID, 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, CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID, 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, CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID, 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..4d72aced3fc
--- /dev/null
+++ b/intern/cycles/kernel/integrator/shadow_catcher.h
@@ -0,0 +1,116 @@
+/*
+ * 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/write_passes.h"
+#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_HIT) {
+ 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;
+}
+
+#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;
+}
+
+/* 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_global float *ccl_restrict render_buffer)
+{
+ kernel_assert(kernel_data.film.pass_shadow_catcher_sample_count != PASS_UNUSED);
+ kernel_assert(kernel_data.film.pass_shadow_catcher_matte != PASS_UNUSED);
+
+ 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;
+
+ /* 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_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..86fcabdcd82
--- /dev/null
+++ b/intern/cycles/kernel/integrator/shadow_state_template.h
@@ -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.
+ */
+
+/********************************* 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, uint32_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, packed_float3, throughput, KERNEL_FEATURE_PATH_TRACING)
+/* Throughput for shadow pass. */
+KERNEL_STRUCT_MEMBER(shadow_path,
+ packed_float3,
+ unshadowed_throughput,
+ KERNEL_FEATURE_SHADOW_PASS | KERNEL_FEATURE_AO_ADDITIVE)
+/* Ratio of throughput to distinguish diffuse / glossy / transmission render passes. */
+KERNEL_STRUCT_MEMBER(shadow_path, packed_float3, pass_diffuse_weight, KERNEL_FEATURE_LIGHT_PASSES)
+KERNEL_STRUCT_MEMBER(shadow_path, packed_float3, pass_glossy_weight, 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, packed_float3, P, KERNEL_FEATURE_PATH_TRACING)
+KERNEL_STRUCT_MEMBER(shadow_ray, packed_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_MEMBER(shadow_ray, int, object, 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..ed2a0be3068
--- /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 int IntegratorState;
+typedef int ConstIntegratorState;
+typedef int IntegratorShadowState;
+typedef 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/state_template.h b/intern/cycles/kernel/integrator/state_template.h
new file mode 100644
index 00000000000..bd18a7498a3
--- /dev/null
+++ b/intern/cycles/kernel/integrator/state_template.h
@@ -0,0 +1,112 @@
+
+/*
+ * 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.
+ */
+
+/************************************ Path State *****************************/
+
+KERNEL_STRUCT_BEGIN(path)
+/* Index of a pixel within the device render buffer where this path will write its result.
+ * To get an actual offset within the buffer the value needs to be multiplied by the
+ * `kernel_data.film.pass_stride`.
+ *
+ * The multiplication is delayed for later, so that state can use 32bit integer. */
+KERNEL_STRUCT_MEMBER(path, uint32_t, render_pixel_index, KERNEL_FEATURE_PATH_TRACING)
+/* Current sample number. */
+KERNEL_STRUCT_MEMBER(path, uint32_t, sample, KERNEL_FEATURE_PATH_TRACING)
+/* Current ray bounce depth. */
+KERNEL_STRUCT_MEMBER(path, uint16_t, bounce, KERNEL_FEATURE_PATH_TRACING)
+/* Current transparent ray bounce depth. */
+KERNEL_STRUCT_MEMBER(path, uint16_t, transparent_bounce, KERNEL_FEATURE_PATH_TRACING)
+/* Current diffuse ray bounce depth. */
+KERNEL_STRUCT_MEMBER(path, uint16_t, diffuse_bounce, KERNEL_FEATURE_PATH_TRACING)
+/* Current glossy ray bounce depth. */
+KERNEL_STRUCT_MEMBER(path, uint16_t, glossy_bounce, KERNEL_FEATURE_PATH_TRACING)
+/* Current transmission ray bounce depth. */
+KERNEL_STRUCT_MEMBER(path, uint16_t, transmission_bounce, KERNEL_FEATURE_PATH_TRACING)
+/* Current volume ray bounce depth. */
+KERNEL_STRUCT_MEMBER(path, uint16_t, volume_bounce, KERNEL_FEATURE_PATH_TRACING)
+/* Current volume bounds ray bounce depth. */
+KERNEL_STRUCT_MEMBER(path, uint16_t, volume_bounds_bounce, KERNEL_FEATURE_PATH_TRACING)
+/* DeviceKernel bit indicating queued kernels. */
+KERNEL_STRUCT_MEMBER(path, uint16_t, queued_kernel, KERNEL_FEATURE_PATH_TRACING)
+/* Random number generator seed. */
+KERNEL_STRUCT_MEMBER(path, uint32_t, rng_hash, KERNEL_FEATURE_PATH_TRACING)
+/* Random number dimension offset. */
+KERNEL_STRUCT_MEMBER(path, uint16_t, rng_offset, KERNEL_FEATURE_PATH_TRACING)
+/* enum PathRayFlag */
+KERNEL_STRUCT_MEMBER(path, uint32_t, flag, KERNEL_FEATURE_PATH_TRACING)
+/* Multiple importance sampling
+ * The PDF of BSDF sampling at the last scatter point, and distance to the
+ * last scatter point minus the last ray segment. This distance lets us
+ * compute the complete distance through transparent surfaces and volumes. */
+KERNEL_STRUCT_MEMBER(path, float, mis_ray_pdf, KERNEL_FEATURE_PATH_TRACING)
+KERNEL_STRUCT_MEMBER(path, float, mis_ray_t, KERNEL_FEATURE_PATH_TRACING)
+/* Filter glossy. */
+KERNEL_STRUCT_MEMBER(path, float, min_ray_pdf, KERNEL_FEATURE_PATH_TRACING)
+/* Continuation probability for path termination. */
+KERNEL_STRUCT_MEMBER(path, float, continuation_probability, KERNEL_FEATURE_PATH_TRACING)
+/* Throughput. */
+KERNEL_STRUCT_MEMBER(path, packed_float3, throughput, KERNEL_FEATURE_PATH_TRACING)
+/* Ratio of throughput to distinguish diffuse / glossy / transmission render passes. */
+KERNEL_STRUCT_MEMBER(path, packed_float3, pass_diffuse_weight, KERNEL_FEATURE_LIGHT_PASSES)
+KERNEL_STRUCT_MEMBER(path, packed_float3, pass_glossy_weight, KERNEL_FEATURE_LIGHT_PASSES)
+/* Denoising. */
+KERNEL_STRUCT_MEMBER(path, packed_float3, denoising_feature_throughput, KERNEL_FEATURE_DENOISING)
+/* Shader sorting. */
+/* TODO: compress as uint16? or leave out entirely and recompute key in sorting code? */
+KERNEL_STRUCT_MEMBER(path, uint32_t, shader_sort_key, KERNEL_FEATURE_PATH_TRACING)
+KERNEL_STRUCT_END(path)
+
+/************************************** Ray ***********************************/
+
+KERNEL_STRUCT_BEGIN(ray)
+KERNEL_STRUCT_MEMBER(ray, packed_float3, P, KERNEL_FEATURE_PATH_TRACING)
+KERNEL_STRUCT_MEMBER(ray, packed_float3, D, KERNEL_FEATURE_PATH_TRACING)
+KERNEL_STRUCT_MEMBER(ray, float, t, KERNEL_FEATURE_PATH_TRACING)
+KERNEL_STRUCT_MEMBER(ray, float, time, KERNEL_FEATURE_PATH_TRACING)
+KERNEL_STRUCT_MEMBER(ray, float, dP, KERNEL_FEATURE_PATH_TRACING)
+KERNEL_STRUCT_MEMBER(ray, float, dD, KERNEL_FEATURE_PATH_TRACING)
+KERNEL_STRUCT_END(ray)
+
+/*************************** Intersection result ******************************/
+
+/* Result from scene intersection. */
+KERNEL_STRUCT_BEGIN(isect)
+KERNEL_STRUCT_MEMBER(isect, float, t, KERNEL_FEATURE_PATH_TRACING)
+KERNEL_STRUCT_MEMBER(isect, float, u, KERNEL_FEATURE_PATH_TRACING)
+KERNEL_STRUCT_MEMBER(isect, float, v, KERNEL_FEATURE_PATH_TRACING)
+KERNEL_STRUCT_MEMBER(isect, int, prim, KERNEL_FEATURE_PATH_TRACING)
+KERNEL_STRUCT_MEMBER(isect, int, object, KERNEL_FEATURE_PATH_TRACING)
+KERNEL_STRUCT_MEMBER(isect, int, type, KERNEL_FEATURE_PATH_TRACING)
+KERNEL_STRUCT_END(isect)
+
+/*************** Subsurface closure state for subsurface kernel ***************/
+
+KERNEL_STRUCT_BEGIN(subsurface)
+KERNEL_STRUCT_MEMBER(subsurface, packed_float3, albedo, KERNEL_FEATURE_SUBSURFACE)
+KERNEL_STRUCT_MEMBER(subsurface, packed_float3, radius, KERNEL_FEATURE_SUBSURFACE)
+KERNEL_STRUCT_MEMBER(subsurface, float, anisotropy, KERNEL_FEATURE_SUBSURFACE)
+KERNEL_STRUCT_MEMBER(subsurface, packed_float3, Ng, KERNEL_FEATURE_SUBSURFACE)
+KERNEL_STRUCT_END(subsurface)
+
+/********************************** Volume Stack ******************************/
+
+KERNEL_STRUCT_BEGIN(volume_stack)
+KERNEL_STRUCT_ARRAY_MEMBER(volume_stack, int, object, KERNEL_FEATURE_VOLUME)
+KERNEL_STRUCT_ARRAY_MEMBER(volume_stack, int, shader, KERNEL_FEATURE_VOLUME)
+KERNEL_STRUCT_END_ARRAY(volume_stack,
+ KERNEL_STRUCT_VOLUME_STACK_SIZE,
+ KERNEL_STRUCT_VOLUME_STACK_SIZE)
diff --git a/intern/cycles/kernel/integrator/state_util.h b/intern/cycles/kernel/integrator/state_util.h
new file mode 100644
index 00000000000..99dae83233c
--- /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 IntegratorState 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 for performance. */
+ 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
+
+ return to_state;
+}
+
+#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..6c0f815afea
--- /dev/null
+++ b/intern/cycles/kernel/integrator/subsurface.h
@@ -0,0 +1,203 @@
+/*
+ * 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;
+
+ 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
+
+ if (sd->flag & SD_BACKFACING) {
+ path_flag |= PATH_RAY_SUBSURFACE_BACKFACING;
+ }
+
+ 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, pass_diffuse_weight) = one_float3();
+ INTEGRATOR_STATE_WRITE(state, path, pass_glossy_weight) = zero_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);
+
+ integrator_volume_stack_update_for_subsurface(kg, state, 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..f5641d1fa5e
--- /dev/null
+++ b/intern/cycles/kernel/integrator/subsurface_disk.h
@@ -0,0 +1,214 @@
+/*
+ * 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);
+ const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
+
+ /* 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;
+ ray.self.object = OBJECT_NONE;
+ ray.self.prim = PRIM_NONE;
+ ray.self.light_object = OBJECT_NONE;
+ ray.self.light_prim = OBJECT_NONE;
+
+ /* 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 (path_flag & PATH_RAY_SUBSURFACE_BACKFACING) {
+ hit_Ng = -hit_Ng;
+ }
+ 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 and MetalRT where it already is. */
+#ifdef __KERNEL_GPU_RAYTRACING__
+ (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..993c54d9050
--- /dev/null
+++ b/intern/cycles/kernel/integrator/subsurface_random_walk.h
@@ -0,0 +1,475 @@
+/*
+ * 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);
+ const int prim = INTEGRATOR_STATE(state, isect, prim);
+
+ /* 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 = P;
+ ray.D = D;
+ ray.t = FLT_MAX;
+ ray.time = time;
+ ray.dP = ray_dP;
+ ray.dD = differential_zero_compact();
+ ray.self.object = object;
+ ray.self.prim = prim;
+ ray.self.light_object = OBJECT_NONE;
+ ray.self.light_prim = PRIM_NONE;
+
+#ifndef __KERNEL_GPU_RAYTRACING__
+ /* 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? */
+ if (bounce == 0) {
+ ray.t = max(t, 10.0f / (min3(sigma_t)));
+ }
+ else {
+ ray.t = t;
+ /* After the first bounce the object can intersect the same surface again */
+ ray.self.object = OBJECT_NONE;
+ ray.self.prim = PRIM_NONE;
+ }
+ scene_intersect_local(kg, &ray, &ss_isect, object, NULL, 1);
+ hit = (ss_isect.num_hits > 0);
+
+ if (hit) {
+#ifdef __KERNEL_GPU_RAYTRACING__
+ /* t is always in world space with OptiX and MetalRT. */
+ 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;
+ }
+
+ /* 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/volume_stack.h b/intern/cycles/kernel/integrator/volume_stack.h
new file mode 100644
index 00000000000..ea3fa901e2d
--- /dev/null
+++ b/intern/cycles/kernel/integrator/volume_stack.h
@@ -0,0 +1,225 @@
+/*
+ * 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
+
+CCL_NAMESPACE_BEGIN
+
+/* Volumetric read/write lambda functions - default implementations */
+#ifndef VOLUME_READ_LAMBDA
+# define VOLUME_READ_LAMBDA(function_call) \
+ auto volume_read_lambda_pass = [=](const int i) { return function_call; };
+# define VOLUME_WRITE_LAMBDA(function_call) \
+ auto volume_write_lambda_pass = [=](const int i, VolumeStack entry) { function_call; };
+#endif
+
+/* Volume Stack
+ *
+ * This is an array of object/shared ID's that the current segment of the path
+ * is inside of. */
+
+template<typename StackReadOp, typename StackWriteOp>
+ccl_device void volume_stack_enter_exit(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ StackReadOp stack_read,
+ StackWriteOp stack_write)
+{
+ /* todo: we should have some way for objects to indicate if they want the
+ * world shader to work inside them. excluding it by default is problematic
+ * because non-volume objects can't be assumed to be closed manifolds */
+ if (!(sd->flag & SD_HAS_VOLUME)) {
+ return;
+ }
+
+ if (sd->flag & SD_BACKFACING) {
+ /* Exit volume object: remove from stack. */
+ for (int i = 0;; i++) {
+ VolumeStack entry = stack_read(i);
+ if (entry.shader == SHADER_NONE) {
+ break;
+ }
+
+ if (entry.object == sd->object) {
+ /* Shift back next stack entries. */
+ do {
+ entry = stack_read(i + 1);
+ stack_write(i, entry);
+ i++;
+ } while (entry.shader != SHADER_NONE);
+
+ return;
+ }
+ }
+ }
+ else {
+ /* Enter volume object: add to stack. */
+ int i;
+ for (i = 0;; i++) {
+ VolumeStack entry = stack_read(i);
+ if (entry.shader == SHADER_NONE) {
+ break;
+ }
+
+ /* Already in the stack? then we have nothing to do. */
+ if (entry.object == sd->object) {
+ return;
+ }
+ }
+
+ /* If we exceed the stack limit, ignore. */
+ if (i >= kernel_data.volume_stack_size - 1) {
+ return;
+ }
+
+ /* Add to the end of the stack. */
+ const VolumeStack new_entry = {sd->object, sd->shader};
+ const VolumeStack empty_entry = {OBJECT_NONE, SHADER_NONE};
+ stack_write(i, new_entry);
+ stack_write(i + 1, empty_entry);
+ }
+}
+
+ccl_device void volume_stack_enter_exit(KernelGlobals kg,
+ IntegratorState state,
+ ccl_private const ShaderData *sd)
+{
+ VOLUME_READ_LAMBDA(integrator_state_read_volume_stack(state, i))
+ VOLUME_WRITE_LAMBDA(integrator_state_write_volume_stack(state, i, entry))
+ volume_stack_enter_exit(kg, sd, volume_read_lambda_pass, volume_write_lambda_pass);
+}
+
+ccl_device void shadow_volume_stack_enter_exit(KernelGlobals kg,
+ IntegratorShadowState state,
+ ccl_private const ShaderData *sd)
+{
+ VOLUME_READ_LAMBDA(integrator_state_read_shadow_volume_stack(state, i))
+ VOLUME_WRITE_LAMBDA(integrator_state_write_shadow_volume_stack(state, i, entry))
+ volume_stack_enter_exit(kg, sd, volume_read_lambda_pass, volume_write_lambda_pass);
+}
+
+/* Clean stack after the last bounce.
+ *
+ * It is expected that all volumes are closed manifolds, so at the time when ray
+ * hits nothing (for example, it is a last bounce which goes to environment) the
+ * only expected volume in the stack is the world's one. All the rest volume
+ * entries should have been exited already.
+ *
+ * This isn't always true because of ray intersection precision issues, which
+ * could lead us to an infinite non-world volume in the stack, causing render
+ * artifacts.
+ *
+ * Use this function after the last bounce to get rid of all volumes apart from
+ * the world's one after the last bounce to avoid render artifacts.
+ */
+ccl_device_inline void volume_stack_clean(KernelGlobals kg, IntegratorState state)
+{
+ if (kernel_data.background.volume_shader != SHADER_NONE) {
+ /* Keep the world's volume in stack. */
+ INTEGRATOR_STATE_ARRAY_WRITE(state, volume_stack, 1, shader) = SHADER_NONE;
+ }
+ else {
+ INTEGRATOR_STATE_ARRAY_WRITE(state, volume_stack, 0, shader) = SHADER_NONE;
+ }
+}
+
+template<typename StackReadOp>
+ccl_device float volume_stack_step_size(KernelGlobals kg, StackReadOp stack_read)
+{
+ float step_size = FLT_MAX;
+
+ for (int i = 0;; i++) {
+ VolumeStack entry = stack_read(i);
+ if (entry.shader == SHADER_NONE) {
+ break;
+ }
+
+ int shader_flag = kernel_tex_fetch(__shaders, (entry.shader & SHADER_MASK)).flags;
+
+ bool heterogeneous = false;
+
+ if (shader_flag & SD_HETEROGENEOUS_VOLUME) {
+ heterogeneous = true;
+ }
+ else if (shader_flag & SD_NEED_VOLUME_ATTRIBUTES) {
+ /* We want to render world or objects without any volume grids
+ * as homogeneous, but can only verify this at run-time since other
+ * heterogeneous volume objects may be using the same shader. */
+ int object = entry.object;
+ if (object != OBJECT_NONE) {
+ int object_flag = kernel_tex_fetch(__object_flag, object);
+ if (object_flag & SD_OBJECT_HAS_VOLUME_ATTRIBUTES) {
+ heterogeneous = true;
+ }
+ }
+ }
+
+ if (heterogeneous) {
+ float object_step_size = object_volume_step_size(kg, entry.object);
+ object_step_size *= kernel_data.integrator.volume_step_rate;
+ step_size = fminf(object_step_size, step_size);
+ }
+ }
+
+ return step_size;
+}
+
+typedef enum VolumeSampleMethod {
+ VOLUME_SAMPLE_NONE = 0,
+ VOLUME_SAMPLE_DISTANCE = (1 << 0),
+ VOLUME_SAMPLE_EQUIANGULAR = (1 << 1),
+ VOLUME_SAMPLE_MIS = (VOLUME_SAMPLE_DISTANCE | VOLUME_SAMPLE_EQUIANGULAR),
+} VolumeSampleMethod;
+
+ccl_device VolumeSampleMethod volume_stack_sample_method(KernelGlobals kg, IntegratorState state)
+{
+ VolumeSampleMethod method = VOLUME_SAMPLE_NONE;
+
+ for (int i = 0;; i++) {
+ VolumeStack entry = integrator_state_read_volume_stack(state, i);
+ if (entry.shader == SHADER_NONE) {
+ break;
+ }
+
+ int shader_flag = kernel_tex_fetch(__shaders, (entry.shader & SHADER_MASK)).flags;
+
+ if (shader_flag & SD_VOLUME_MIS) {
+ /* Multiple importance sampling. */
+ return VOLUME_SAMPLE_MIS;
+ }
+ else if (shader_flag & SD_VOLUME_EQUIANGULAR) {
+ /* Distance + equiangular sampling -> multiple importance sampling. */
+ if (method == VOLUME_SAMPLE_DISTANCE) {
+ return VOLUME_SAMPLE_MIS;
+ }
+
+ /* Only equiangular sampling. */
+ method = VOLUME_SAMPLE_EQUIANGULAR;
+ }
+ else {
+ /* Distance + equiangular sampling -> multiple importance sampling. */
+ if (method == VOLUME_SAMPLE_EQUIANGULAR) {
+ return VOLUME_SAMPLE_MIS;
+ }
+
+ /* Distance sampling only. */
+ method = VOLUME_SAMPLE_DISTANCE;
+ }
+ }
+
+ return method;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_accumulate.h b/intern/cycles/kernel/kernel_accumulate.h
deleted file mode 100644
index f4d00e4c20c..00000000000
--- a/intern/cycles/kernel/kernel_accumulate.h
+++ /dev/null
@@ -1,514 +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(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(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(BsdfEval *eval)
-{
- return is_zero(eval->diffuse) && is_zero(eval->glossy);
-}
-
-ccl_device_inline void bsdf_eval_mul(BsdfEval *eval, float value)
-{
- eval->diffuse *= value;
- eval->glossy *= value;
-}
-
-ccl_device_inline void bsdf_eval_mul3(BsdfEval *eval, float3 value)
-{
- eval->diffuse *= value;
- eval->glossy *= value;
-}
-
-ccl_device_inline float3 bsdf_eval_sum(const BsdfEval *eval)
-{
- return eval->diffuse + eval->glossy;
-}
-
-ccl_device_inline float3 bsdf_eval_diffuse_glossy_ratio(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(const KernelGlobals *kg, 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(
- INTEGRATOR_STATE_CONST_ARGS, ccl_global float *ccl_restrict render_buffer)
-{
- const uint32_t render_pixel_index = INTEGRATOR_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(INTEGRATOR_STATE_CONST_ARGS,
- 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(INTEGRATOR_STATE_PASS,
- render_buffer);
-
- return atomic_fetch_and_add_uint32((uint *)(buffer) + kernel_data.film.pass_sample_count, 1);
-}
-
-ccl_device void kernel_accum_adaptive_buffer(INTEGRATOR_STATE_CONST_ARGS,
- 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;
- }
-
- const int sample = INTEGRATOR_STATE(path, sample);
- 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(INTEGRATOR_STATE_CONST_ARGS,
- 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(INTEGRATOR_STATE_PASS)) {
- 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(INTEGRATOR_STATE_PASS)) {
- kernel_write_pass_float3(buffer + kernel_data.film.pass_shadow_catcher, contribution);
- return true;
- }
-
- return false;
-}
-
-ccl_device bool kernel_accum_shadow_catcher_transparent(INTEGRATOR_STATE_CONST_ARGS,
- 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 (INTEGRATOR_STATE(path, flag) & PATH_RAY_SHADOW_CATCHER_BACKGROUND) {
- return true;
- }
-
- /* Matte pass. */
- if (kernel_shadow_catcher_is_matte_path(INTEGRATOR_STATE_PASS)) {
- 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(INTEGRATOR_STATE_PASS)) {
- /* 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(INTEGRATOR_STATE_CONST_ARGS,
- 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(INTEGRATOR_STATE_PASS)) {
- 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(INTEGRATOR_STATE_CONST_ARGS,
- const float3 contribution,
- ccl_global float *ccl_restrict buffer)
-{
-#ifdef __SHADOW_CATCHER__
- if (kernel_accum_shadow_catcher(INTEGRATOR_STATE_PASS, 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(INTEGRATOR_STATE_PASS, contribution, buffer);
-}
-
-/* Write combined pass with transparency. */
-ccl_device_inline void kernel_accum_combined_transparent_pass(INTEGRATOR_STATE_CONST_ARGS,
- const float3 contribution,
- const float transparent,
- ccl_global float *ccl_restrict
- buffer)
-{
-#ifdef __SHADOW_CATCHER__
- if (kernel_accum_shadow_catcher_transparent(
- INTEGRATOR_STATE_PASS, 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(INTEGRATOR_STATE_PASS, contribution, buffer);
-}
-
-/* Write background or emission to appropriate pass. */
-ccl_device_inline void kernel_accum_emission_or_background_pass(INTEGRATOR_STATE_CONST_ARGS,
- float3 contribution,
- ccl_global float *ccl_restrict
- buffer,
- const int pass)
-{
- if (!(kernel_data.film.light_pass_flag & PASS_ANY)) {
- return;
- }
-
-#ifdef __PASSES__
- const int path_flag = INTEGRATOR_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(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(path, bounce) == 1) ?
- kernel_data.film.pass_glossy_direct :
- kernel_data.film.pass_glossy_indirect) :
- ((INTEGRATOR_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(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(path, bounce) == 1) ? kernel_data.film.pass_diffuse_direct :
- kernel_data.film.pass_diffuse_indirect;
- if (pass_offset != PASS_UNUSED) {
- contribution *= INTEGRATOR_STATE(path, diffuse_glossy_ratio);
- }
- }
- else if (path_flag & PATH_RAY_VOLUME_PASS) {
- /* Indirectly visible through volume. */
- pass_offset = (INTEGRATOR_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(INTEGRATOR_STATE_CONST_ARGS,
- ccl_global float *ccl_restrict render_buffer)
-{
- /* The throughput for shadow paths already contains the light shader evaluation. */
- float3 contribution = INTEGRATOR_STATE(shadow_path, throughput);
- kernel_accum_clamp(kg, &contribution, INTEGRATOR_STATE(shadow_path, bounce));
-
- ccl_global float *buffer = kernel_accum_pixel_render_buffer(INTEGRATOR_STATE_PASS,
- render_buffer);
-
- kernel_accum_combined_pass(INTEGRATOR_STATE_PASS, contribution, buffer);
-
-#ifdef __PASSES__
- if (kernel_data.film.light_pass_flag & PASS_ANY) {
- const int path_flag = INTEGRATOR_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(shadow_path, bounce) == 0) ?
- kernel_data.film.pass_glossy_direct :
- kernel_data.film.pass_glossy_indirect) :
- ((INTEGRATOR_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(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(shadow_path, bounce) == 0) ?
- kernel_data.film.pass_diffuse_direct :
- kernel_data.film.pass_diffuse_indirect;
- if (pass_offset != PASS_UNUSED) {
- contribution *= INTEGRATOR_STATE(shadow_path, diffuse_glossy_ratio);
- }
- }
- else if (path_flag & PATH_RAY_VOLUME_PASS) {
- /* Indirectly visible through volume. */
- pass_offset = (INTEGRATOR_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(shadow_path, unshadowed_throughput);
- const float3 shadowed_throughput = INTEGRATOR_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(INTEGRATOR_STATE_CONST_ARGS,
- const float transparent,
- ccl_global float *ccl_restrict render_buffer)
-{
- ccl_global float *buffer = kernel_accum_pixel_render_buffer(INTEGRATOR_STATE_PASS,
- render_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(INTEGRATOR_STATE_PASS, transparent, buffer);
-}
-
-/* Write background contribution to render buffer.
- *
- * Includes transparency, matching kernel_accum_transparent. */
-ccl_device_inline void kernel_accum_background(INTEGRATOR_STATE_CONST_ARGS,
- const float3 L,
- const float transparent,
- const bool is_transparent_background_ray,
- ccl_global float *ccl_restrict render_buffer)
-{
- float3 contribution = INTEGRATOR_STATE(path, throughput) * L;
- kernel_accum_clamp(kg, &contribution, INTEGRATOR_STATE(path, bounce) - 1);
-
- ccl_global float *buffer = kernel_accum_pixel_render_buffer(INTEGRATOR_STATE_PASS,
- render_buffer);
-
- if (is_transparent_background_ray) {
- kernel_accum_transparent(INTEGRATOR_STATE_PASS, transparent, render_buffer);
- }
- else {
- kernel_accum_combined_transparent_pass(
- INTEGRATOR_STATE_PASS, contribution, transparent, buffer);
- }
- kernel_accum_emission_or_background_pass(
- INTEGRATOR_STATE_PASS, contribution, buffer, kernel_data.film.pass_background);
-}
-
-/* Write emission to render buffer. */
-ccl_device_inline void kernel_accum_emission(INTEGRATOR_STATE_CONST_ARGS,
- const float3 throughput,
- const float3 L,
- ccl_global float *ccl_restrict render_buffer)
-{
- float3 contribution = throughput * L;
- kernel_accum_clamp(kg, &contribution, INTEGRATOR_STATE(path, bounce) - 1);
-
- ccl_global float *buffer = kernel_accum_pixel_render_buffer(INTEGRATOR_STATE_PASS,
- render_buffer);
-
- kernel_accum_combined_pass(INTEGRATOR_STATE_PASS, contribution, buffer);
- kernel_accum_emission_or_background_pass(
- INTEGRATOR_STATE_PASS, 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 7d71907effe..00000000000
--- a/intern/cycles/kernel/kernel_adaptive_sampling.h
+++ /dev/null
@@ -1,159 +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(INTEGRATOR_STATE_CONST_ARGS,
- 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(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(const 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(const 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(const 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 abb1ba455e6..00000000000
--- a/intern/cycles/kernel/kernel_bake.h
+++ /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.
- */
-
-#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(const KernelGlobals *kg,
- ccl_global const KernelShaderEvalInput *input,
- ccl_global float4 *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(INTEGRATOR_STATE_PASS_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] += make_float4(D.x, D.y, D.z, 0.0f);
-}
-
-ccl_device void kernel_background_evaluate(const KernelGlobals *kg,
- ccl_global const KernelShaderEvalInput *input,
- ccl_global float4 *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 int path_flag = PATH_RAY_EMISSION;
- shader_eval_surface<KERNEL_FEATURE_NODE_MASK_SURFACE_LIGHT>(
- INTEGRATOR_STATE_PASS_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] += make_float4(color.x, color.y, color.z, 0.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 7be5da8fe6d..00000000000
--- a/intern/cycles/kernel/kernel_camera.h
+++ /dev/null
@@ -1,519 +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(const KernelGlobals *ccl_restrict kg,
- float raster_x,
- float raster_y,
- float lens_u,
- float lens_v,
- ccl_addr_space 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(const KernelGlobals *ccl_restrict kg,
- float raster_x,
- float raster_y,
- float lens_u,
- float lens_v,
- ccl_addr_space 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__
- const ccl_global DecomposedTransform *cam_motion,
-#endif
- float raster_x,
- float raster_y,
- float lens_u,
- float lens_v,
- ccl_addr_space 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(const KernelGlobals *ccl_restrict kg,
- int x,
- int y,
- float filter_u,
- float filter_v,
- float lens_u,
- float lens_v,
- float time,
- ccl_addr_space 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__
- const ccl_global 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(const 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(const 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(const 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(const 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(const KernelGlobals *kg, 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 960774e0741..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(const 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(const 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/kernel_differential.h
deleted file mode 100644
index db4e110bd10..00000000000
--- a/intern/cycles/kernel/kernel_differential.h
+++ /dev/null
@@ -1,166 +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
-
-/* See "Tracing Ray Differentials", Homan Igehy, 1999. */
-
-ccl_device void differential_transfer(ccl_addr_space differential3 *surface_dP,
- const differential3 ray_dP,
- float3 ray_D,
- const differential3 ray_dD,
- float3 surface_Ng,
- float ray_t)
-{
- /* ray differential transfer through homogeneous medium, to
- * compute dPdx/dy at a shading point from the incoming ray */
-
- float3 tmp = ray_D / dot(ray_D, surface_Ng);
- float3 tmpx = ray_dP.dx + ray_t * ray_dD.dx;
- float3 tmpy = ray_dP.dy + ray_t * ray_dD.dy;
-
- surface_dP->dx = tmpx - dot(tmpx, surface_Ng) * tmp;
- surface_dP->dy = tmpy - dot(tmpy, surface_Ng) * tmp;
-}
-
-ccl_device void differential_incoming(ccl_addr_space differential3 *dI, const differential3 dD)
-{
- /* compute dIdx/dy at a shading point, we just need to negate the
- * differential of the ray direction */
-
- dI->dx = -dD.dx;
- dI->dy = -dD.dy;
-}
-
-ccl_device void differential_dudv(ccl_addr_space differential *du,
- ccl_addr_space differential *dv,
- float3 dPdu,
- float3 dPdv,
- differential3 dP,
- float3 Ng)
-{
- /* now we have dPdx/dy from the ray differential transfer, and dPdu/dv
- * from the primitive, we can compute dudx/dy and dvdx/dy. these are
- * mainly used for differentials of arbitrary mesh attributes. */
-
- /* find most stable axis to project to 2D */
- float xn = fabsf(Ng.x);
- float yn = fabsf(Ng.y);
- float zn = fabsf(Ng.z);
-
- if (zn < xn || zn < yn) {
- if (yn < xn || yn < zn) {
- dPdu.x = dPdu.y;
- dPdv.x = dPdv.y;
- dP.dx.x = dP.dx.y;
- dP.dy.x = dP.dy.y;
- }
-
- dPdu.y = dPdu.z;
- dPdv.y = dPdv.z;
- dP.dx.y = dP.dx.z;
- dP.dy.y = dP.dy.z;
- }
-
- /* using Cramer's rule, we solve for dudx and dvdx in a 2x2 linear system,
- * and the same for dudy and dvdy. the denominator is the same for both
- * solutions, so we compute it only once.
- *
- * dP.dx = dPdu * dudx + dPdv * dvdx;
- * dP.dy = dPdu * dudy + dPdv * dvdy; */
-
- float det = (dPdu.x * dPdv.y - dPdv.x * dPdu.y);
-
- if (det != 0.0f)
- det = 1.0f / det;
-
- du->dx = (dP.dx.x * dPdv.y - dP.dx.y * dPdv.x) * det;
- dv->dx = (dP.dx.y * dPdu.x - dP.dx.x * dPdu.y) * det;
-
- du->dy = (dP.dy.x * dPdv.y - dP.dy.y * dPdv.x) * det;
- dv->dy = (dP.dy.y * dPdu.x - dP.dy.x * dPdu.y) * det;
-}
-
-ccl_device differential differential_zero()
-{
- differential d;
- d.dx = 0.0f;
- d.dy = 0.0f;
-
- return d;
-}
-
-ccl_device differential3 differential3_zero()
-{
- differential3 d;
- d.dx = zero_float3();
- d.dy = zero_float3();
-
- return d;
-}
-
-/* Compact ray differentials that are just a scale to reduce memory usage and
- * access cost in GPU.
- *
- * See above for more accurate reference implementations.
- *
- * TODO: also store the more compact version in ShaderData and recompute where
- * needed? */
-
-ccl_device_forceinline float differential_zero_compact()
-{
- return 0.0f;
-}
-
-ccl_device_forceinline float differential_make_compact(const differential3 D)
-{
- return 0.5f * (len(D.dx) + len(D.dy));
-}
-
-ccl_device_forceinline void differential_transfer_compact(ccl_addr_space differential3 *surface_dP,
- const float ray_dP,
- const float3 /* ray_D */,
- const float ray_dD,
- const float3 surface_Ng,
- const float ray_t)
-{
- /* ray differential transfer through homogeneous medium, to
- * compute dPdx/dy at a shading point from the incoming ray */
- float scale = ray_dP + ray_t * ray_dD;
-
- float3 dx, dy;
- make_orthonormals(surface_Ng, &dx, &dy);
- surface_dP->dx = dx * scale;
- surface_dP->dy = dy * scale;
-}
-
-ccl_device_forceinline void differential_incoming_compact(ccl_addr_space differential3 *dI,
- const float3 D,
- const float dD)
-{
- /* compute dIdx/dy at a shading point, we just need to negate the
- * differential of the ray direction */
-
- float3 dx, dy;
- make_orthonormals(D, &dx, &dy);
-
- dI->dx = dD * dx;
- dI->dy = dD * dy;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_emission.h b/intern/cycles/kernel/kernel_emission.h
deleted file mode 100644
index d62285d173d..00000000000
--- a/intern/cycles/kernel/kernel_emission.h
+++ /dev/null
@@ -1,266 +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(INTEGRATOR_STATE_ARGS,
- ShaderData *ccl_restrict emission_sd,
- 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>(
- INTEGRATOR_STATE_PASS, 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) {
- const ccl_global 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(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(const KernelGlobals *ccl_restrict kg,
- const LightSample *ccl_restrict ls,
- 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(const KernelGlobals *ccl_restrict kg,
- 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(const KernelGlobals *ccl_restrict kg,
- 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(const ShaderData *ccl_restrict sd,
- const LightSample *ccl_restrict ls,
- const float3 P,
- 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(const KernelGlobals *ccl_restrict kg,
- const ShaderData *ccl_restrict sd,
- const LightSample *ccl_restrict ls,
- 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(const KernelGlobals *ccl_restrict kg,
- const ShaderData *ccl_restrict sd,
- const LightSample *ccl_restrict ls,
- const float3 P,
- 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 e8f4a21878e..00000000000
--- a/intern/cycles/kernel/kernel_film.h
+++ /dev/null
@@ -1,529 +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(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 = *((const uint *)(buffer + kfilm_convert->pass_sample_count));
- return 1.0f / sample_count;
- }
-
- return 1.0f;
-}
-
-ccl_device_inline float film_get_scale_exposure(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(
- const KernelFilmConvert *ccl_restrict kfilm_convert,
- ccl_global const float *ccl_restrict buffer,
- float *ccl_restrict scale,
- 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 = *((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(const KernelFilmConvert *ccl_restrict
- kfilm_convert,
- ccl_global const float *ccl_restrict buffer,
- 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);
-
- 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(const KernelFilmConvert *ccl_restrict
- kfilm_convert,
- ccl_global const float *ccl_restrict buffer,
- 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);
-
- 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(
- const KernelFilmConvert *ccl_restrict kfilm_convert,
- ccl_global const float *ccl_restrict buffer,
- 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);
-
- 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(const KernelFilmConvert *ccl_restrict
- kfilm_convert,
- ccl_global const float *ccl_restrict buffer,
- 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);
-
- 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(const KernelFilmConvert *ccl_restrict
- kfilm_convert,
- ccl_global const float *ccl_restrict buffer,
- float *ccl_restrict pixel)
-{
- kernel_assert(kfilm_convert->num_components >= 3);
- kernel_assert(kfilm_convert->pass_offset != PASS_UNUSED);
-
- /* Read light pass. */
- 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) {
- 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) {
- 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(const KernelFilmConvert *ccl_restrict
- kfilm_convert,
- ccl_global const float *ccl_restrict buffer,
- 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);
-
- 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(const KernelFilmConvert *ccl_restrict
- kfilm_convert,
- ccl_global const float *ccl_restrict buffer,
- 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);
-
- const float *in = buffer + kfilm_convert->pass_offset;
- 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(const KernelFilmConvert *ccl_restrict
- kfilm_convert,
- ccl_global const float *ccl_restrict buffer,
- 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);
-
- 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(const KernelFilmConvert *ccl_restrict
- kfilm_convert,
- ccl_global const float *ccl_restrict buffer,
- 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);
-
- 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(const KernelFilmConvert *ccl_restrict
- kfilm_convert,
- ccl_global const float *ccl_restrict buffer,
- 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;
- }
-
- 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(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(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(
- 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(
- const KernelFilmConvert *ccl_restrict kfilm_convert,
- ccl_global const float *ccl_restrict buffer,
- 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(
- const KernelFilmConvert *ccl_restrict kfilm_convert,
- ccl_global const float *ccl_restrict buffer,
- 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(
- const KernelFilmConvert *ccl_restrict kfilm_convert,
- ccl_global const float *ccl_restrict buffer,
- 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_id_passes.h b/intern/cycles/kernel/kernel_id_passes.h
deleted file mode 100644
index ed01f494f98..00000000000
--- a/intern/cycles/kernel/kernel_id_passes.h
+++ /dev/null
@@ -1,106 +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
-
-CCL_NAMESPACE_BEGIN
-
-/* Element of ID pass stored in the render buffers.
- * It is `float2` semantically, but it must be unaligned since the offset of ID passes in the
- * render buffers might not meet expected by compiler alignment. */
-typedef struct IDPassBufferElement {
- float x;
- float y;
-} IDPassBufferElement;
-
-ccl_device_inline void kernel_write_id_slots(ccl_global float *buffer,
- int num_slots,
- float id,
- float weight)
-{
- kernel_assert(id != ID_NONE);
- if (weight == 0.0f) {
- return;
- }
-
- for (int slot = 0; slot < num_slots; slot++) {
- ccl_global IDPassBufferElement *id_buffer = (ccl_global IDPassBufferElement *)buffer;
-#ifdef __ATOMIC_PASS_WRITE__
- /* If the loop reaches an empty slot, the ID isn't in any slot yet - so add it! */
- if (id_buffer[slot].x == ID_NONE) {
- /* Use an atomic to claim this slot.
- * If a different thread got here first, try again from this slot on. */
- float old_id = atomic_compare_and_swap_float(buffer + slot * 2, ID_NONE, id);
- if (old_id != ID_NONE && old_id != id) {
- continue;
- }
- atomic_add_and_fetch_float(buffer + slot * 2 + 1, weight);
- break;
- }
- /* If there already is a slot for that ID, add the weight.
- * If no slot was found, add it to the last. */
- else if (id_buffer[slot].x == id || slot == num_slots - 1) {
- atomic_add_and_fetch_float(buffer + slot * 2 + 1, weight);
- break;
- }
-#else /* __ATOMIC_PASS_WRITE__ */
- /* If the loop reaches an empty slot, the ID isn't in any slot yet - so add it! */
- if (id_buffer[slot].x == ID_NONE) {
- id_buffer[slot].x = id;
- id_buffer[slot].y = weight;
- break;
- }
- /* If there already is a slot for that ID, add the weight.
- * If no slot was found, add it to the last. */
- else if (id_buffer[slot].x == id || slot == num_slots - 1) {
- id_buffer[slot].y += weight;
- break;
- }
-#endif /* __ATOMIC_PASS_WRITE__ */
- }
-}
-
-ccl_device_inline void kernel_sort_id_slots(ccl_global float *buffer, int num_slots)
-{
- ccl_global IDPassBufferElement *id_buffer = (ccl_global IDPassBufferElement *)buffer;
- for (int slot = 1; slot < num_slots; ++slot) {
- if (id_buffer[slot].x == ID_NONE) {
- return;
- }
- /* Since we're dealing with a tiny number of elements, insertion sort should be fine. */
- int i = slot;
- while (i > 0 && id_buffer[i].y > id_buffer[i - 1].y) {
- const IDPassBufferElement swap = id_buffer[i];
- id_buffer[i] = id_buffer[i - 1];
- id_buffer[i - 1] = swap;
- --i;
- }
- }
-}
-
-/* post-sorting for Cryptomatte */
-ccl_device_inline void kernel_cryptomatte_post(const KernelGlobals *kg,
- ccl_global float *render_buffer,
- int pixel_index)
-{
- const int pass_stride = kernel_data.film.pass_stride;
- const uint64_t render_buffer_offset = (uint64_t)pixel_index * pass_stride;
- ccl_global float *cryptomatte_buffer = render_buffer + render_buffer_offset +
- kernel_data.film.pass_cryptomatte;
- kernel_sort_id_slots(cryptomatte_buffer, 2 * kernel_data.film.cryptomatte_depth);
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_jitter.h b/intern/cycles/kernel/kernel_jitter.h
deleted file mode 100644
index 1beaf3cc2b2..00000000000
--- a/intern/cycles/kernel/kernel_jitter.h
+++ /dev/null
@@ -1,165 +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(const 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(
- const KernelGlobals *kg, uint sample, uint rng_hash, uint dimension, float *x, 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 52f641634b9..00000000000
--- a/intern/cycles/kernel/kernel_light.h
+++ /dev/null
@@ -1,877 +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(const KernelGlobals *kg,
- const int lamp,
- const float randu,
- const float randv,
- const float3 P,
- const int path_flag,
- 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(const KernelGlobals *ccl_restrict kg,
- const Ray *ccl_restrict ray,
- Intersection *ccl_restrict isect,
- const int last_prim,
- const int last_object,
- const int last_type,
- const int 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(const KernelGlobals *ccl_restrict kg,
- const float3 ray_D,
- const int lamp,
- LightSample *ccl_restrict ls)
-{
- const ccl_global 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(const KernelGlobals *ccl_restrict kg,
- const Intersection *ccl_restrict isect,
- const float3 ray_P,
- const float3 ray_D,
- LightSample *ccl_restrict ls)
-{
- const int lamp = isect->prim;
- const ccl_global 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(
- const 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(const 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(const KernelGlobals *kg,
- 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(const KernelGlobals *kg,
- int prim,
- int object,
- float randu,
- float randv,
- float time,
- 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(const KernelGlobals *kg, 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(const 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(const KernelGlobals *kg,
- float randu,
- const float randv,
- const float time,
- const float3 P,
- const int bounce,
- const int path_flag,
- LightSample *ls)
-{
- /* Sample light index from distribution. */
- const int index = light_distribution_sample(kg, &randu);
- const ccl_global 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(const KernelGlobals *kg,
- float randu,
- const float randv,
- const float time,
- const float3 P,
- const int bounce,
- const int path_flag,
- 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(const KernelGlobals *kg,
- float randu,
- const float randv,
- const float time,
- const float3 P,
- const int bounce,
- const int path_flag,
- 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(const KernelGlobals *kg,
- const float randu,
- const float randv,
- const float time,
- const float3 P,
- 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 493ed560bc6..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(const KernelGlobals *kg,
- float randu,
- float randv,
- 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(const 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(
- const KernelGlobals *kg, float3 P, int index, float3 *lightpos, 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(
- const KernelGlobals *kg, float3 P, float3 direction, int ignore_portal, 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(const 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(const KernelGlobals *kg,
- float3 P,
- float randu,
- float randv,
- int num_possible,
- int *sampled_portal,
- 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(const KernelGlobals *kg,
- float randu,
- float randv,
- 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(const 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(const KernelGlobals *kg, float3 P, float randu, float randv, 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(const 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 765d8f5338e..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,
- 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,
- float3 *lightP,
- float3 *axisu,
- 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(const 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 33d9d5ae1f0..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(const 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(
- const 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 b158f4c4fd3..00000000000
--- a/intern/cycles/kernel/kernel_montecarlo.h
+++ /dev/null
@@ -1,301 +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(float *x, 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, float3 *a, 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, float3 *omega_in, 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, float3 *omega_in, 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, float3 *omega_in, 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 67466b28170..00000000000
--- a/intern/cycles/kernel/kernel_passes.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.
- */
-
-#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(
- INTEGRATOR_STATE_CONST_ARGS, ccl_global float *ccl_restrict render_buffer)
-{
- const uint32_t render_pixel_index = INTEGRATOR_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(
- INTEGRATOR_STATE_ARGS, const ShaderData *sd, ccl_global float *ccl_restrict render_buffer)
-{
- if (!(INTEGRATOR_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(INTEGRATOR_STATE_PASS, 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++) {
- 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)) {
- MicrofacetBsdf *bsdf = (MicrofacetBsdf *)sc;
- closure_albedo *= bsdf->extra->fresnel_color;
- }
- else if (sc->type == CLOSURE_BSDF_PRINCIPLED_SHEEN_ID) {
- PrincipledSheenBsdf *bsdf = (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(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(path, flag) &= ~PATH_RAY_DENOISING_FEATURES;
- }
- else {
- INTEGRATOR_STATE_WRITE(path, denoising_feature_throughput) *= specular_albedo;
- }
-}
-
-ccl_device_forceinline void kernel_write_denoising_features_volume(INTEGRATOR_STATE_ARGS,
- const float3 albedo,
- const bool scatter,
- ccl_global float *ccl_restrict
- render_buffer)
-{
- ccl_global float *buffer = kernel_pass_pixel_render_buffer(INTEGRATOR_STATE_PASS, render_buffer);
- const float3 denoising_feature_throughput = INTEGRATOR_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(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(
- INTEGRATOR_STATE_ARGS, 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(INTEGRATOR_STATE_PASS, sd->object_flag)) {
- return;
- }
-
- ccl_global float *buffer = kernel_pass_pixel_render_buffer(INTEGRATOR_STATE_PASS, 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(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(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(INTEGRATOR_STATE_ARGS,
- const ShaderData *sd,
- ccl_global float *ccl_restrict render_buffer)
-{
-#ifdef __PASSES__
- const int path_flag = INTEGRATOR_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(INTEGRATOR_STATE_PASS, 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(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(path, flag) |= PATH_RAY_SINGLE_PASS_DONE;
- }
- }
-
- if (kernel_data.film.cryptomatte_passes) {
- const float3 throughput = INTEGRATOR_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(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(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(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(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 ebb2c0df4f1..00000000000
--- a/intern/cycles/kernel/kernel_path_state.h
+++ /dev/null
@@ -1,367 +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(INTEGRATOR_STATE_ARGS)
-{
- INTEGRATOR_STATE_WRITE(path, queued_kernel) = 0;
- INTEGRATOR_STATE_WRITE(shadow_path, queued_kernel) = 0;
-}
-
-/* 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(INTEGRATOR_STATE_ARGS,
- const ccl_global 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(path, render_pixel_index) = render_pixel_index;
-
- path_state_init_queues(INTEGRATOR_STATE_PASS);
-}
-
-/* Initialize the rest of the path state needed to continue the path integration. */
-ccl_device_inline void path_state_init_integrator(INTEGRATOR_STATE_ARGS,
- const int sample,
- const uint rng_hash)
-{
- INTEGRATOR_STATE_WRITE(path, sample) = sample;
- INTEGRATOR_STATE_WRITE(path, bounce) = 0;
- INTEGRATOR_STATE_WRITE(path, diffuse_bounce) = 0;
- INTEGRATOR_STATE_WRITE(path, glossy_bounce) = 0;
- INTEGRATOR_STATE_WRITE(path, transmission_bounce) = 0;
- INTEGRATOR_STATE_WRITE(path, transparent_bounce) = 0;
- INTEGRATOR_STATE_WRITE(path, volume_bounce) = 0;
- INTEGRATOR_STATE_WRITE(path, volume_bounds_bounce) = 0;
- INTEGRATOR_STATE_WRITE(path, rng_hash) = rng_hash;
- INTEGRATOR_STATE_WRITE(path, rng_offset) = PRNG_BASE_NUM;
- INTEGRATOR_STATE_WRITE(path, flag) = PATH_RAY_CAMERA | PATH_RAY_MIS_SKIP |
- PATH_RAY_TRANSPARENT_BACKGROUND;
- INTEGRATOR_STATE_WRITE(path, mis_ray_pdf) = 0.0f;
- INTEGRATOR_STATE_WRITE(path, mis_ray_t) = 0.0f;
- INTEGRATOR_STATE_WRITE(path, min_ray_pdf) = FLT_MAX;
- INTEGRATOR_STATE_WRITE(path, throughput) = make_float3(1.0f, 1.0f, 1.0f);
-
- if (kernel_data.kernel_features & KERNEL_FEATURE_VOLUME) {
- INTEGRATOR_STATE_ARRAY_WRITE(volume_stack, 0, object) = OBJECT_NONE;
- INTEGRATOR_STATE_ARRAY_WRITE(volume_stack, 0, shader) = kernel_data.background.volume_shader;
- INTEGRATOR_STATE_ARRAY_WRITE(volume_stack, 1, object) = OBJECT_NONE;
- INTEGRATOR_STATE_ARRAY_WRITE(volume_stack, 1, shader) = SHADER_NONE;
- }
-
-#ifdef __DENOISING_FEATURES__
- if (kernel_data.kernel_features & KERNEL_FEATURE_DENOISING) {
- INTEGRATOR_STATE_WRITE(path, flag) |= PATH_RAY_DENOISING_FEATURES;
- INTEGRATOR_STATE_WRITE(path, denoising_feature_throughput) = one_float3();
- }
-#endif
-}
-
-ccl_device_inline void path_state_next(INTEGRATOR_STATE_ARGS, int label)
-{
- uint32_t flag = INTEGRATOR_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(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(path, flag) = flag;
- INTEGRATOR_STATE_WRITE(path, transparent_bounce) = transparent_bounce;
- /* Random number generator next bounce. */
- INTEGRATOR_STATE_WRITE(path, rng_offset) += PRNG_BOUNCE_NUM;
- return;
- }
-
- uint32_t bounce = INTEGRATOR_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(path, volume_bounce) + 1;
- INTEGRATOR_STATE_WRITE(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(path, diffuse_bounce) + 1;
- INTEGRATOR_STATE_WRITE(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(path, glossy_bounce) + 1;
- INTEGRATOR_STATE_WRITE(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(path, transmission_bounce) + 1;
- INTEGRATOR_STATE_WRITE(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(path, flag) = flag;
- INTEGRATOR_STATE_WRITE(path, bounce) = bounce;
-
- /* Random number generator next bounce. */
- INTEGRATOR_STATE_WRITE(path, rng_offset) += PRNG_BOUNCE_NUM;
-}
-
-#ifdef __VOLUME__
-ccl_device_inline bool path_state_volume_next(INTEGRATOR_STATE_ARGS)
-{
- /* 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(path, volume_bounds_bounce) + 1;
- INTEGRATOR_STATE_WRITE(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(path, rng_offset) += PRNG_BOUNCE_NUM;
- }
-
- return true;
-}
-#endif
-
-ccl_device_inline uint path_state_ray_visibility(INTEGRATOR_STATE_CONST_ARGS)
-{
- const uint32_t path_flag = INTEGRATOR_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(INTEGRATOR_STATE_CONST_ARGS,
- const uint32_t path_flag)
-{
- if (path_flag & PATH_RAY_TRANSPARENT) {
- const uint32_t transparent_bounce = INTEGRATOR_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(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(path, throughput)))), 1.0f);
-}
-
-ccl_device_inline bool path_state_ao_bounce(INTEGRATOR_STATE_CONST_ARGS)
-{
- if (!kernel_data.integrator.ao_bounces) {
- return false;
- }
-
- const int bounce = INTEGRATOR_STATE(path, bounce) - INTEGRATOR_STATE(path, transmission_bounce) -
- (INTEGRATOR_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(INTEGRATOR_STATE_CONST_ARGS, RNGState *rng_state)
-{
- rng_state->rng_hash = INTEGRATOR_STATE(path, rng_hash);
- rng_state->rng_offset = INTEGRATOR_STATE(path, rng_offset);
- rng_state->sample = INTEGRATOR_STATE(path, sample);
-}
-
-ccl_device_inline void shadow_path_state_rng_load(INTEGRATOR_STATE_CONST_ARGS, RNGState *rng_state)
-{
- const uint shadow_bounces = INTEGRATOR_STATE(shadow_path, transparent_bounce) -
- INTEGRATOR_STATE(path, transparent_bounce);
-
- rng_state->rng_hash = INTEGRATOR_STATE(path, rng_hash);
- rng_state->rng_offset = INTEGRATOR_STATE(path, rng_offset) + PRNG_BOUNCE_NUM * shadow_bounces;
- rng_state->sample = INTEGRATOR_STATE(path, sample);
-}
-
-ccl_device_inline float path_state_rng_1D(const KernelGlobals *kg,
- 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(
- const KernelGlobals *kg, const RNGState *rng_state, int dimension, float *fx, 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(const KernelGlobals *kg,
- 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(const KernelGlobals *kg,
- 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(const KernelGlobals *kg,
- const RNGState *rng_state,
- int branch,
- int num_branches,
- int dimension,
- float *fx,
- 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(const KernelGlobals *kg,
- 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_projection.h b/intern/cycles/kernel/kernel_projection.h
deleted file mode 100644
index 192bf7ca5aa..00000000000
--- a/intern/cycles/kernel/kernel_projection.h
+++ /dev/null
@@ -1,258 +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
-
-/* Spherical coordinates <-> Cartesian direction. */
-
-ccl_device float2 direction_to_spherical(float3 dir)
-{
- float theta = safe_acosf(dir.z);
- float phi = atan2f(dir.x, dir.y);
-
- return make_float2(theta, phi);
-}
-
-ccl_device float3 spherical_to_direction(float theta, float phi)
-{
- float sin_theta = sinf(theta);
- return make_float3(sin_theta * cosf(phi), sin_theta * sinf(phi), cosf(theta));
-}
-
-/* Equirectangular coordinates <-> Cartesian direction */
-
-ccl_device float2 direction_to_equirectangular_range(float3 dir, float4 range)
-{
- if (is_zero(dir))
- return zero_float2();
-
- float u = (atan2f(dir.y, dir.x) - range.y) / range.x;
- float v = (acosf(dir.z / len(dir)) - range.w) / range.z;
-
- return make_float2(u, v);
-}
-
-ccl_device float3 equirectangular_range_to_direction(float u, float v, float4 range)
-{
- float phi = range.x * u + range.y;
- float theta = range.z * v + range.w;
- float sin_theta = sinf(theta);
- return make_float3(sin_theta * cosf(phi), sin_theta * sinf(phi), cosf(theta));
-}
-
-ccl_device float2 direction_to_equirectangular(float3 dir)
-{
- return direction_to_equirectangular_range(dir, make_float4(-M_2PI_F, M_PI_F, -M_PI_F, M_PI_F));
-}
-
-ccl_device float3 equirectangular_to_direction(float u, float v)
-{
- return equirectangular_range_to_direction(u, v, make_float4(-M_2PI_F, M_PI_F, -M_PI_F, M_PI_F));
-}
-
-/* Fisheye <-> Cartesian direction */
-
-ccl_device float2 direction_to_fisheye(float3 dir, float fov)
-{
- float r = atan2f(sqrtf(dir.y * dir.y + dir.z * dir.z), dir.x) / fov;
- float phi = atan2f(dir.z, dir.y);
-
- float u = r * cosf(phi) + 0.5f;
- float v = r * sinf(phi) + 0.5f;
-
- return make_float2(u, v);
-}
-
-ccl_device float3 fisheye_to_direction(float u, float v, float fov)
-{
- u = (u - 0.5f) * 2.0f;
- v = (v - 0.5f) * 2.0f;
-
- float r = sqrtf(u * u + v * v);
-
- if (r > 1.0f)
- return zero_float3();
-
- float phi = safe_acosf((r != 0.0f) ? u / r : 0.0f);
- float theta = r * fov * 0.5f;
-
- if (v < 0.0f)
- phi = -phi;
-
- return make_float3(cosf(theta), -cosf(phi) * sinf(theta), sinf(phi) * sinf(theta));
-}
-
-ccl_device float2 direction_to_fisheye_equisolid(float3 dir, float lens, float width, float height)
-{
- float theta = safe_acosf(dir.x);
- float r = 2.0f * lens * sinf(theta * 0.5f);
- float phi = atan2f(dir.z, dir.y);
-
- float u = r * cosf(phi) / width + 0.5f;
- float v = r * sinf(phi) / height + 0.5f;
-
- return make_float2(u, v);
-}
-
-ccl_device_inline float3
-fisheye_equisolid_to_direction(float u, float v, float lens, float fov, float width, float height)
-{
- u = (u - 0.5f) * width;
- v = (v - 0.5f) * height;
-
- float rmax = 2.0f * lens * sinf(fov * 0.25f);
- float r = sqrtf(u * u + v * v);
-
- if (r > rmax)
- return zero_float3();
-
- float phi = safe_acosf((r != 0.0f) ? u / r : 0.0f);
- float theta = 2.0f * asinf(r / (2.0f * lens));
-
- if (v < 0.0f)
- phi = -phi;
-
- return make_float3(cosf(theta), -cosf(phi) * sinf(theta), sinf(phi) * sinf(theta));
-}
-
-/* Mirror Ball <-> Cartesion direction */
-
-ccl_device float3 mirrorball_to_direction(float u, float v)
-{
- /* point on sphere */
- float3 dir;
-
- dir.x = 2.0f * u - 1.0f;
- dir.z = 2.0f * v - 1.0f;
-
- if (dir.x * dir.x + dir.z * dir.z > 1.0f)
- return zero_float3();
-
- dir.y = -sqrtf(max(1.0f - dir.x * dir.x - dir.z * dir.z, 0.0f));
-
- /* reflection */
- float3 I = make_float3(0.0f, -1.0f, 0.0f);
-
- return 2.0f * dot(dir, I) * dir - I;
-}
-
-ccl_device float2 direction_to_mirrorball(float3 dir)
-{
- /* inverse of mirrorball_to_direction */
- dir.y -= 1.0f;
-
- float div = 2.0f * sqrtf(max(-0.5f * dir.y, 0.0f));
- if (div > 0.0f)
- dir /= div;
-
- float u = 0.5f * (dir.x + 1.0f);
- float v = 0.5f * (dir.z + 1.0f);
-
- return make_float2(u, v);
-}
-
-ccl_device_inline float3 panorama_to_direction(ccl_constant KernelCamera *cam, float u, float v)
-{
- switch (cam->panorama_type) {
- case PANORAMA_EQUIRECTANGULAR:
- return equirectangular_range_to_direction(u, v, cam->equirectangular_range);
- case PANORAMA_MIRRORBALL:
- return mirrorball_to_direction(u, v);
- case PANORAMA_FISHEYE_EQUIDISTANT:
- return fisheye_to_direction(u, v, cam->fisheye_fov);
- case PANORAMA_FISHEYE_EQUISOLID:
- default:
- return fisheye_equisolid_to_direction(
- u, v, cam->fisheye_lens, cam->fisheye_fov, cam->sensorwidth, cam->sensorheight);
- }
-}
-
-ccl_device_inline float2 direction_to_panorama(ccl_constant KernelCamera *cam, float3 dir)
-{
- switch (cam->panorama_type) {
- case PANORAMA_EQUIRECTANGULAR:
- return direction_to_equirectangular_range(dir, cam->equirectangular_range);
- case PANORAMA_MIRRORBALL:
- return direction_to_mirrorball(dir);
- case PANORAMA_FISHEYE_EQUIDISTANT:
- return direction_to_fisheye(dir, cam->fisheye_fov);
- case PANORAMA_FISHEYE_EQUISOLID:
- default:
- return direction_to_fisheye_equisolid(
- dir, cam->fisheye_lens, cam->sensorwidth, cam->sensorheight);
- }
-}
-
-ccl_device_inline void spherical_stereo_transform(ccl_constant KernelCamera *cam,
- float3 *P,
- float3 *D)
-{
- float interocular_offset = cam->interocular_offset;
-
- /* Interocular offset of zero means either non stereo, or stereo without
- * spherical stereo. */
- kernel_assert(interocular_offset != 0.0f);
-
- if (cam->pole_merge_angle_to > 0.0f) {
- const float pole_merge_angle_from = cam->pole_merge_angle_from,
- pole_merge_angle_to = cam->pole_merge_angle_to;
- float altitude = fabsf(safe_asinf((*D).z));
- if (altitude > pole_merge_angle_to) {
- interocular_offset = 0.0f;
- }
- else if (altitude > pole_merge_angle_from) {
- float fac = (altitude - pole_merge_angle_from) /
- (pole_merge_angle_to - pole_merge_angle_from);
- float fade = cosf(fac * M_PI_2_F);
- interocular_offset *= fade;
- }
- }
-
- float3 up = make_float3(0.0f, 0.0f, 1.0f);
- float3 side = normalize(cross(*D, up));
- float3 stereo_offset = side * interocular_offset;
-
- *P += stereo_offset;
-
- /* Convergence distance is FLT_MAX in the case of parallel convergence mode,
- * no need to modify direction in this case either. */
- const float convergence_distance = cam->convergence_distance;
-
- if (convergence_distance != FLT_MAX) {
- float3 screen_offset = convergence_distance * (*D);
- *D = normalize(screen_offset - stereo_offset);
- }
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_random.h b/intern/cycles/kernel/kernel_random.h
deleted file mode 100644
index 240c92bf9d0..00000000000
--- a/intern/cycles/kernel/kernel_random.h
+++ /dev/null
@@ -1,219 +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(const 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(const 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(
- const KernelGlobals *kg, uint rng_hash, int sample, int dimension, float *fx, 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(const KernelGlobals *ccl_restrict 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 float lcg_step_float_addrspace(ccl_addr_space uint *rng)
-{
- /* Implicit mod 2^32 */
- *rng = (1103515245 * (*rng) + 12345);
- return (float)*rng * (1.0f / (float)0xFFFFFFFF);
-}
-
-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 8bad9c34d74..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(ShaderData *sd)
-{
- /* Merge identical closures to save closure space with stacked volumes. */
- for (int i = 0; i < sd->num_closure; i++) {
- ShaderClosure *sci = &sd->closure[i];
-
- if (sci->type != CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID) {
- continue;
- }
-
- for (int j = i + 1; j < sd->num_closure; j++) {
- ShaderClosure *scj = &sd->closure[j];
- if (sci->type != scj->type) {
- continue;
- }
-
- const HenyeyGreensteinVolume *hgi = (const HenyeyGreensteinVolume *)sci;
- const HenyeyGreensteinVolume *hgj = (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(ShaderVolumePhases *ccl_restrict phases,
- const ShaderData *ccl_restrict sd)
-{
- phases->num_closure = 0;
-
- for (int i = 0; i < sd->num_closure; i++) {
- const ShaderClosure *from_sc = &sd->closure[i];
- const HenyeyGreensteinVolume *from_hg = (const HenyeyGreensteinVolume *)from_sc;
-
- if (from_sc->type == CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID) {
- 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(INTEGRATOR_STATE_CONST_ARGS, 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(path, bounce) + INTEGRATOR_STATE(path, transparent_bounce) == 0 &&
- sd->num_closure > 1) {
- float sum = 0.0f;
-
- for (int i = 0; i < sd->num_closure; i++) {
- 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++) {
- 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(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++) {
- 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(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) || CLOSURE_IS_BSDF_BSSRDF(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(const KernelGlobals *kg,
- ShaderData *sd,
- const float3 omega_in,
- const bool is_transmission,
- const ShaderClosure *skip_sc,
- 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++) {
- 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) ||
- CLOSURE_IS_BSDF_BSSRDF(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(const KernelGlobals *kg,
- ShaderData *sd,
- const float3 omega_in,
- const bool is_transmission,
- 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 const ShaderClosure *shader_bsdf_bssrdf_pick(const ShaderData *ccl_restrict sd,
- 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++) {
- 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++) {
- 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(const ShaderData *ccl_restrict sd,
- 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++) {
- 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(const KernelGlobals *kg,
- ShaderData *sd,
- const ShaderClosure *sc,
- float randu,
- float randv,
- BsdfEval *bsdf_eval,
- float3 *omega_in,
- differential3 *domega_in,
- 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) ||
- CLOSURE_IS_BSDF_BSSRDF(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(const ShaderData *sd)
-{
- float roughness = 0.0f;
- float sum_weight = 0.0f;
-
- for (int i = 0; i < sd->num_closure; i++) {
- 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(const KernelGlobals *kg, 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(const KernelGlobals *kg, ShaderData *sd)
-{
- if (sd->flag & SD_TRANSPARENT) {
- for (int i = 0; i < sd->num_closure; i++) {
- 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(const KernelGlobals *kg, 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(const KernelGlobals *kg, const ShaderData *sd)
-{
- float3 eval = zero_float3();
-
- for (int i = 0; i < sd->num_closure; i++) {
- const ShaderClosure *sc = &sd->closure[i];
-
- if (CLOSURE_IS_BSDF_DIFFUSE(sc->type) || CLOSURE_IS_BSSRDF(sc->type) ||
- CLOSURE_IS_BSDF_BSSRDF(sc->type))
- eval += sc->weight;
- }
-
- return eval;
-}
-
-ccl_device float3 shader_bsdf_glossy(const KernelGlobals *kg, const ShaderData *sd)
-{
- float3 eval = zero_float3();
-
- for (int i = 0; i < sd->num_closure; i++) {
- const ShaderClosure *sc = &sd->closure[i];
-
- if (CLOSURE_IS_BSDF_GLOSSY(sc->type))
- eval += sc->weight;
- }
-
- return eval;
-}
-
-ccl_device float3 shader_bsdf_transmission(const KernelGlobals *kg, const ShaderData *sd)
-{
- float3 eval = zero_float3();
-
- for (int i = 0; i < sd->num_closure; i++) {
- 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(const KernelGlobals *kg, const ShaderData *sd)
-{
- float3 N = zero_float3();
-
- for (int i = 0; i < sd->num_closure; i++) {
- 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(const KernelGlobals *kg, const ShaderData *sd)
-{
- float3 N = zero_float3();
-
- for (int i = 0; i < sd->num_closure; i++) {
- const ShaderClosure *sc = &sd->closure[i];
- if (CLOSURE_IS_BSDF_DIFFUSE(sc->type)) {
- const DiffuseBsdf *bsdf = (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(const ShaderData *sd)
-{
- float3 N = zero_float3();
-
- for (int i = 0; i < sd->num_closure; i++) {
- const ShaderClosure *sc = &sd->closure[i];
-
- if (CLOSURE_IS_BSSRDF(sc->type)) {
- const Bssrdf *bssrdf = (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(const KernelGlobals *kg, int shader, 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(const ShaderData *sd)
-{
- if (sd->flag & SD_EMISSION) {
- return sd->closure_emission_background;
- }
- else {
- return zero_float3();
- }
-}
-
-/* Emission */
-
-ccl_device float3 shader_emissive_eval(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(const KernelGlobals *kg, 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++) {
- 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++) {
- const ShaderClosure *sc = &sd->closure[i];
- if (CLOSURE_IS_HOLDOUT(sc->type)) {
- weight += sc->weight;
- }
- }
- }
-
- return weight;
-}
-
-/* Surface Evaluation */
-
-template<uint node_feature_mask>
-ccl_device void shader_eval_surface(INTEGRATOR_STATE_CONST_ARGS,
- ShaderData *ccl_restrict sd,
- ccl_global float *ccl_restrict buffer,
- int 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(INTEGRATOR_STATE_PASS, sd, path_flag);
- }
- else {
- OSLShader::eval_surface(INTEGRATOR_STATE_PASS, sd, path_flag);
- }
- }
- else
-#endif
- {
-#ifdef __SVM__
- svm_eval_nodes<node_feature_mask, SHADER_TYPE_SURFACE>(
- INTEGRATOR_STATE_PASS, 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 {
- DiffuseBsdf *bsdf = (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
- }
-
- if (KERNEL_NODES_FEATURE(BSDF) && (sd->flag & SD_BSDF_NEEDS_LCG)) {
- sd->lcg_state = lcg_state_init(INTEGRATOR_STATE(path, rng_hash),
- INTEGRATOR_STATE(path, rng_offset),
- INTEGRATOR_STATE(path, sample),
- 0xb4bc3953);
- }
-}
-
-/* Volume */
-
-#ifdef __VOLUME__
-
-ccl_device_inline float _shader_volume_phase_multi_eval(const ShaderData *sd,
- const ShaderVolumePhases *phases,
- const float3 omega_in,
- int skip_phase,
- BsdfEval *result_eval,
- float sum_pdf,
- float sum_sample_weight)
-{
- for (int i = 0; i < phases->num_closure; i++) {
- if (i == skip_phase)
- continue;
-
- 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(const KernelGlobals *kg,
- const ShaderData *sd,
- const ShaderVolumePhases *phases,
- const float3 omega_in,
- 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(const KernelGlobals *kg,
- const ShaderData *sd,
- const ShaderVolumePhases *phases,
- float randu,
- float randv,
- BsdfEval *phase_eval,
- float3 *omega_in,
- differential3 *domega_in,
- 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++) {
- 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++) {
- 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 */
- 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(const KernelGlobals *kg,
- const ShaderData *sd,
- const ShaderVolumeClosure *sc,
- float randu,
- float randv,
- BsdfEval *phase_eval,
- float3 *omega_in,
- differential3 *domega_in,
- 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>
-ccl_device_inline void shader_eval_volume(INTEGRATOR_STATE_CONST_ARGS,
- ShaderData *ccl_restrict sd,
- const int 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 shaderdata 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(INTEGRATOR_STATE_PASS, sd, path_flag);
- }
- else
-# endif
- {
- svm_eval_nodes<KERNEL_FEATURE_NODE_MASK_VOLUME, SHADER_TYPE_VOLUME>(
- INTEGRATOR_STATE_PASS, 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 */
-
-ccl_device void shader_eval_displacement(INTEGRATOR_STATE_CONST_ARGS, 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(INTEGRATOR_STATE_PASS, sd);
- else
-# endif
- {
- svm_eval_nodes<KERNEL_FEATURE_NODE_MASK_DISPLACEMENT, SHADER_TYPE_DISPLACEMENT>(
- INTEGRATOR_STATE_PASS, sd, NULL, 0);
- }
-#endif
-}
-
-/* Transparent Shadows */
-
-#ifdef __TRANSPARENT_SHADOWS__
-ccl_device bool shader_transparent_shadow(const KernelGlobals *kg, Intersection *isect)
-{
- return (intersection_get_shader_flags(kg, isect) & SD_HAS_TRANSPARENT_SHADOW) != 0;
-}
-#endif /* __TRANSPARENT_SHADOWS__ */
-
-ccl_device float shader_cryptomatte_id(const 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 824749818a4..00000000000
--- a/intern/cycles/kernel/kernel_shadow_catcher.h
+++ /dev/null
@@ -1,116 +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(INTEGRATOR_STATE_ARGS,
- 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 int path_flag = INTEGRATOR_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(INTEGRATOR_STATE_CONST_ARGS)
-{
- if (INTEGRATOR_PATH_IS_TERMINATED && INTEGRATOR_SHADOW_PATH_IS_TERMINATED) {
- return false;
- }
-
- const int path_flag = INTEGRATOR_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(INTEGRATOR_STATE_ARGS, const int object_flags)
-{
-#ifdef __SHADOW_CATCHER__
-
- if (!kernel_shadow_catcher_is_path_split_bounce(INTEGRATOR_STATE_PASS, 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(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(INTEGRATOR_STATE_PASS);
-
- return true;
-#else
- (void)object_flags;
- return false;
-#endif
-}
-
-#ifdef __SHADOW_CATCHER__
-
-ccl_device_forceinline bool kernel_shadow_catcher_is_matte_path(INTEGRATOR_STATE_CONST_ARGS)
-{
- return (INTEGRATOR_STATE(path, flag) & PATH_RAY_SHADOW_CATCHER_HIT) == 0;
-}
-
-ccl_device_forceinline bool kernel_shadow_catcher_is_object_pass(INTEGRATOR_STATE_CONST_ARGS)
-{
- return INTEGRATOR_STATE(path, flag) & PATH_RAY_SHADOW_CATCHER_PASS;
-}
-
-#endif /* __SHADOW_CATCHER__ */
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_textures.h b/intern/cycles/kernel/kernel_textures.h
deleted file mode 100644
index bf9b94c1753..00000000000
--- a/intern/cycles/kernel/kernel_textures.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.
- */
-
-#ifndef KERNEL_TEX
-# define KERNEL_TEX(type, name)
-#endif
-
-/* bvh */
-KERNEL_TEX(float4, __bvh_nodes)
-KERNEL_TEX(float4, __bvh_leaf_nodes)
-KERNEL_TEX(float4, __prim_tri_verts)
-KERNEL_TEX(uint, __prim_tri_index)
-KERNEL_TEX(uint, __prim_type)
-KERNEL_TEX(uint, __prim_visibility)
-KERNEL_TEX(uint, __prim_index)
-KERNEL_TEX(uint, __prim_object)
-KERNEL_TEX(uint, __object_node)
-KERNEL_TEX(float2, __prim_time)
-
-/* objects */
-KERNEL_TEX(KernelObject, __objects)
-KERNEL_TEX(Transform, __object_motion_pass)
-KERNEL_TEX(DecomposedTransform, __object_motion)
-KERNEL_TEX(uint, __object_flag)
-KERNEL_TEX(float, __object_volume_step)
-
-/* cameras */
-KERNEL_TEX(DecomposedTransform, __camera_motion)
-
-/* triangles */
-KERNEL_TEX(uint, __tri_shader)
-KERNEL_TEX(float4, __tri_vnormal)
-KERNEL_TEX(uint4, __tri_vindex)
-KERNEL_TEX(uint, __tri_patch)
-KERNEL_TEX(float2, __tri_patch_uv)
-
-/* curves */
-KERNEL_TEX(float4, __curves)
-KERNEL_TEX(float4, __curve_keys)
-
-/* patches */
-KERNEL_TEX(uint, __patches)
-
-/* attributes */
-KERNEL_TEX(uint4, __attributes_map)
-KERNEL_TEX(float, __attributes_float)
-KERNEL_TEX(float2, __attributes_float2)
-KERNEL_TEX(float4, __attributes_float3)
-KERNEL_TEX(uchar4, __attributes_uchar4)
-
-/* lights */
-KERNEL_TEX(KernelLightDistribution, __light_distribution)
-KERNEL_TEX(KernelLight, __lights)
-KERNEL_TEX(float2, __light_background_marginal_cdf)
-KERNEL_TEX(float2, __light_background_conditional_cdf)
-
-/* particles */
-KERNEL_TEX(KernelParticle, __particles)
-
-/* shaders */
-KERNEL_TEX(uint4, __svm_nodes)
-KERNEL_TEX(KernelShader, __shaders)
-
-/* lookup tables */
-KERNEL_TEX(float, __lookup_table)
-
-/* sobol */
-KERNEL_TEX(float, __sample_pattern_lut)
-
-/* image textures */
-KERNEL_TEX(TextureInfo, __texture_info)
-
-/* ies lights */
-KERNEL_TEX(float, __ies)
-
-#undef KERNEL_TEX
diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h
deleted file mode 100644
index 3cc42bf7a85..00000000000
--- a/intern/cycles/kernel/kernel_types.h
+++ /dev/null
@@ -1,1547 +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 VOLUME_STACK_SIZE 4
-
-/* 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 = (1 << 0),
- PATH_RAY_REFLECT = (1 << 1),
- PATH_RAY_TRANSMIT = (1 << 2),
- PATH_RAY_DIFFUSE = (1 << 3),
- PATH_RAY_GLOSSY = (1 << 4),
- PATH_RAY_SINGULAR = (1 << 5),
- PATH_RAY_TRANSPARENT = (1 << 6),
- PATH_RAY_VOLUME_SCATTER = (1 << 7),
-
- /* Shadow ray visibility. */
- PATH_RAY_SHADOW_OPAQUE = (1 << 8),
- PATH_RAY_SHADOW_TRANSPARENT = (1 << 9),
- 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 OBB). */
- PATH_RAY_NODE_UNALIGNED = (1 << 10),
-
- /* 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 = ((1 << 11) - 1),
-
- /* --------------------------------------------------------------------
- * 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 = (1 << 11),
-
- /* Diffuse bounce earlier in the path, skip SSS to improve performance
- * and avoid branching twice with disk sampling SSS. */
- PATH_RAY_DIFFUSE_ANCESTOR = (1 << 12),
-
- /* Single pass has been written. */
- PATH_RAY_SINGLE_PASS_DONE = (1 << 13),
-
- /* Zero background alpha, for camera or transparent glass rays. */
- PATH_RAY_TRANSPARENT_BACKGROUND = (1 << 14),
-
- /* Terminate ray immediately at next bounce. */
- PATH_RAY_TERMINATE_ON_NEXT_SURFACE = (1 << 15),
- PATH_RAY_TERMINATE_IN_NEXT_VOLUME = (1 << 16),
-
- /* 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 = (1 << 17),
-
- /* Terminate ray immediately after volume shading. */
- PATH_RAY_TERMINATE_AFTER_VOLUME = (1 << 18),
-
- /* 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 = (1 << 19),
-
- /* Perform subsurface scattering. */
- PATH_RAY_SUBSURFACE = (1 << 20),
-
- /* Contribute to denoising features. */
- PATH_RAY_DENOISING_FEATURES = (1 << 21),
-
- /* Render pass categories. */
- PATH_RAY_REFLECT_PASS = (1 << 22),
- PATH_RAY_TRANSMISSION_PASS = (1 << 23),
- PATH_RAY_VOLUME_PASS = (1 << 24),
- PATH_RAY_ANY_PASS = (PATH_RAY_REFLECT_PASS | PATH_RAY_TRANSMISSION_PASS | PATH_RAY_VOLUME_PASS),
-
- /* Shadow ray is for a light or surface. */
- PATH_RAY_SHADOW_FOR_LIGHT = (1 << 25),
-
- /* A shadow catcher object was hit and the path was split into two. */
- PATH_RAY_SHADOW_CATCHER_HIT = (1 << 26),
-
- /* 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 = (1 << 27),
-
- /* Path is evaluating background for an approximate shadow catcher with non-transparent film. */
- PATH_RAY_SHADOW_CATCHER_BACKGROUND = (1 << 28),
-};
-
-/* 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_RENDER_TIME,
- 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 {
-#ifdef __EMBREE__
- float3 Ng;
-#endif
- 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_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
-
-#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 ccl_addr_space 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 ccl_addr_space 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 KernelGlobals *osl_globals;
- const struct IntegratorStateCPU *osl_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 ccl_addr_space struct ccl_align(16) ShaderDataTinyStorage
-{
- char pad[sizeof(ShaderData) - sizeof(ShaderClosure) * MAX_CLOSURE];
-}
-ShaderDataTinyStorage;
-#define AS_SHADER_DATA(shader_data_tiny_storage) ((ShaderData *)shader_data_tiny_storage)
-
-/* Compact volume closures storage.
- *
- * Used for decoupled direct/indirect light closure storage. */
-
-ccl_addr_space struct ShaderVolumeClosure {
- float3 weight;
- float sample_weight;
- float g;
-};
-
-ccl_addr_space struct ShaderVolumePhases {
- ShaderVolumeClosure closure[MAX_VOLUME_CLOSURE];
- int num_closure;
-};
-
-/* Volume Stack */
-
-#ifdef __VOLUME__
-typedef struct VolumeStack {
- int object;
- int shader;
-} VolumeStack;
-#endif
-
-/* Struct to gather multiple nearby intersections. */
-typedef struct LocalIntersection {
- Ray ray;
- float3 weight[LOCAL_MAX_HITS];
-
- 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 pad;
-
- 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;
-
- float pad1, pad2;
-} KernelObject;
-static_assert_align(KernelObject, 16);
-
-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_RESET,
- DEVICE_KERNEL_INTEGRATOR_SHADOW_CATCHER_COUNT_POSSIBLE_SPLITS,
-
- DEVICE_KERNEL_SHADER_EVAL_DISPLACE,
- DEVICE_KERNEL_SHADER_EVAL_BACKGROUND,
-
-#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),
-
- /* Use denoising kernels and output denoising passes. */
- KERNEL_FEATURE_DENOISING = (1U << 8U),
-
- /* Use path tracing kernels. */
- KERNEL_FEATURE_PATH_TRACING = (1U << 9U),
-
- /* BVH/sampling kernel features. */
- KERNEL_FEATURE_HAIR = (1U << 10U),
- KERNEL_FEATURE_HAIR_THICK = (1U << 11U),
- KERNEL_FEATURE_OBJECT_MOTION = (1U << 12U),
- KERNEL_FEATURE_CAMERA_MOTION = (1U << 13U),
-
- /* Denotes whether baking functionality is needed. */
- KERNEL_FEATURE_BAKING = (1U << 14U),
-
- /* Use subsurface scattering materials. */
- KERNEL_FEATURE_SUBSURFACE = (1U << 15U),
-
- /* Use volume materials. */
- KERNEL_FEATURE_VOLUME = (1U << 16U),
-
- /* Use OpenSubdiv patch evaluation */
- KERNEL_FEATURE_PATCH_EVALUATION = (1U << 17U),
-
- /* Use Transparent shadows */
- KERNEL_FEATURE_TRANSPARENT = (1U << 18U),
-
- /* Use shadow catcher. */
- KERNEL_FEATURE_SHADOW_CATCHER = (1U << 19U),
-
- /* Per-uber shader usage flags. */
- KERNEL_FEATURE_PRINCIPLED = (1U << 20U),
-
- /* Light render passes. */
- KERNEL_FEATURE_LIGHT_PASSES = (1U << 21U),
-
- /* Shadow render pass. */
- KERNEL_FEATURE_SHADOW_PASS = (1U << 22U),
-};
-
-/* 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)
-#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)
-#define KERNEL_FEATURE_NODE_MASK_SURFACE \
- (KERNEL_FEATURE_NODE_MASK_SURFACE_SHADOW | KERNEL_FEATURE_NODE_RAYTRACE)
-#define KERNEL_FEATURE_NODE_MASK_VOLUME \
- (KERNEL_FEATURE_NODE_EMISSION | KERNEL_FEATURE_NODE_VOLUME | KERNEL_FEATURE_NODE_VORONOI_EXTRA)
-#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
-
-#define KERNEL_NODES_FEATURE(feature) ((node_feature_mask & (KERNEL_FEATURE_NODE_##feature)) != 0U)
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_work_stealing.h b/intern/cycles/kernel/kernel_work_stealing.h
deleted file mode 100644
index fab0915c38e..00000000000
--- a/intern/cycles/kernel/kernel_work_stealing.h
+++ /dev/null
@@ -1,52 +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.
- */
-
-#pragma once
-
-CCL_NAMESPACE_BEGIN
-
-/*
- * Utility functions for work stealing
- */
-
-/* Map global work index to tile, pixel X/Y and sample. */
-ccl_device_inline void get_work_pixel(ccl_global const KernelWorkTile *tile,
- uint global_work_index,
- ccl_private uint *x,
- ccl_private uint *y,
- ccl_private uint *sample)
-{
-#if 0
- /* Keep threads for the same sample together. */
- uint tile_pixels = tile->w * tile->h;
- uint sample_offset = global_work_index / tile_pixels;
- uint pixel_offset = global_work_index - sample_offset * tile_pixels;
-#else
- /* Keeping threads for the same pixel together.
- * Appears to improve performance by a few % on CUDA and OptiX. */
- uint sample_offset = global_work_index % tile->num_samples;
- uint pixel_offset = global_work_index / tile->num_samples;
-#endif
-
- uint y_offset = pixel_offset / tile->w;
- uint x_offset = pixel_offset - y_offset * tile->w;
-
- *x = tile->x + x_offset;
- *y = tile->y + y_offset;
- *sample = tile->start_sample + sample_offset;
-}
-
-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..07f59ae48c2
--- /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..b9c0b533518
--- /dev/null
+++ b/intern/cycles/kernel/light/light.h
@@ -0,0 +1,924 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 = 1.0f;
+ 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_SPOT) {
+ ls->Ng = make_float3(klight->spot.dir[0], klight->spot.dir[1], klight->spot.dir[2]);
+ float radius = klight->spot.radius;
+
+ if (radius > 0.0f)
+ /* sphere light */
+ ls->P += disk_light_sample(ls->Ng, randu, randv) * radius;
+
+ ls->D = normalize_len(ls->P - P, &ls->t);
+
+ float invarea = klight->spot.invarea;
+ ls->eval_fac = (0.25f * M_1_PI_F) * invarea;
+ ls->pdf = invarea;
+
+ /* spot light attenuation */
+ ls->eval_fac *= spot_light_attenuation(
+ ls->Ng, klight->spot.spot_angle, klight->spot.spot_smooth, -ls->D);
+ if (!in_volume_segment && 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 if (type == LIGHT_POINT) {
+ float3 center = make_float3(klight->co[0], klight->co[1], klight->co[2]);
+ float radius = klight->spot.radius;
+ ls->P = center;
+ float pdf = 1.0;
+
+ if (radius > 0.0f) {
+ ls->Ng = normalize(P - center);
+ ls->P += disk_light_sample(ls->Ng, randu, randv) * radius;
+ pdf = klight->spot.invarea;
+ ls->D = normalize_len(ls->P - P, &ls->t);
+ }
+ else {
+ ls->Ng = normalize(P - center);
+ }
+
+ ls->D = normalize_len(ls->P - P, &ls->t);
+ ls->pdf = pdf;
+ ls->eval_fac = M_1_PI_F * 0.25f * klight->spot.invarea;
+
+ 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 (!in_volume_segment && 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 in_volume_segment || (ls->pdf > 0.0f);
+}
+
+ccl_device bool lights_intersect(KernelGlobals kg,
+ IntegratorState state,
+ 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_SPOT) {
+ /* Spot/Disk light. */
+ const float3 lightP = make_float3(klight->co[0], klight->co[1], klight->co[2]);
+ const float3 lightN = make_float3(
+ klight->spot.dir[0], klight->spot.dir[1], klight->spot.dir[2]);
+ const float radius = klight->spot.radius;
+ if (radius == 0.0f) {
+ continue;
+ }
+
+ /* One sided. */
+ if (dot(ray->D, lightN) >= 0.0f) {
+ continue;
+ }
+
+ float3 P;
+ if (!ray_disk_intersect(ray->P, ray->D, ray->t, lightP, lightN, radius, &P, &t)) {
+ continue;
+ }
+ }
+ else if (type == LIGHT_POINT) {
+ /* Sphere light (aka, aligned disk light). */
+ const float mis_ray_t = INTEGRATOR_STATE(state, path, mis_ray_t);
+ const float3 ray_P = ray->P - ray->D * mis_ray_t;
+
+ 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;
+ const float3 lsN = normalize(ray_P - lightP);
+ if (!ray_disk_intersect(ray->P, ray->D, ray->t, lightP, lsN, 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->eval_fac = ls->pdf;
+ ls->pdf *= kernel_data.integrator.pdf_lights;
+
+ 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 = isect->object;
+ ls->prim = isect->prim;
+ 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_SPOT) {
+ ls->Ng = make_float3(klight->spot.dir[0], klight->spot.dir[1], klight->spot.dir[2]);
+
+ float invarea = klight->spot.invarea;
+ ls->eval_fac = (0.25f * M_1_PI_F) * invarea;
+ ls->pdf = invarea;
+
+ /* spot light attenuation */
+ ls->eval_fac *= spot_light_attenuation(
+ ls->Ng, klight->spot.spot_angle, klight->spot.spot_smooth, -ls->D);
+
+ 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_POINT) {
+ float3 center = make_float3(klight->co[0], klight->co[1], klight->co[2]);
+
+ ls->Ng = normalize(ray_P - center);
+ float invarea = klight->spot.invarea;
+ ls->eval_fac = (0.25f * M_1_PI_F) * invarea;
+ ls->pdf = invarea;
+
+ 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
+ ls->pdf = 0.f;
+ }
+ 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, V[0], V[1], V[2], &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..521ad2f7066
--- /dev/null
+++ b/intern/cycles/kernel/light/sample.h
@@ -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.
+ */
+
+#pragma once
+
+#include "kernel/integrator/path_state.h"
+#include "kernel/integrator/shader_eval.h"
+
+#include "kernel/light/light.h"
+
+#include "kernel/sample/mapping.h"
+#include "kernel/sample/mis.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];
+
+ if (sd->type == PRIMITIVE_MOTION_TRIANGLE) {
+ motion_triangle_vertices_and_normals(kg, sd->object, sd->prim, sd->time, V, N);
+ }
+ else {
+ kernel_assert(sd->type == PRIMITIVE_TRIANGLE);
+ 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 */
+
+ if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
+ 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 = sd->P;
+
+ if ((sd->type & PRIMITIVE_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 < 0) {
+ NL = -NL;
+ }
+ 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 = ls->P - 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;
+
+ /* Fill in intersection surface and light details. */
+ ray->self.prim = sd->prim;
+ ray->self.object = sd->object;
+ ray->self.light_prim = ls->prim;
+ ray->self.light_object = ls->object;
+}
+
+/* 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_device_inline float light_sample_mis_weight_forward(KernelGlobals kg,
+ const float forward_pdf,
+ const float nee_pdf)
+{
+#ifdef WITH_CYCLES_DEBUG
+ if (kernel_data.integrator.direct_light_sampling_type == DIRECT_LIGHT_SAMPLING_FORWARD) {
+ return 1.0f;
+ }
+ else if (kernel_data.integrator.direct_light_sampling_type == DIRECT_LIGHT_SAMPLING_NEE) {
+ return 0.0f;
+ }
+ else
+#endif
+ return power_heuristic(forward_pdf, nee_pdf);
+}
+
+ccl_device_inline float light_sample_mis_weight_nee(KernelGlobals kg,
+ const float nee_pdf,
+ const float forward_pdf)
+{
+#ifdef WITH_CYCLES_DEBUG
+ if (kernel_data.integrator.direct_light_sampling_type == DIRECT_LIGHT_SAMPLING_FORWARD) {
+ return 0.0f;
+ }
+ else if (kernel_data.integrator.direct_light_sampling_type == DIRECT_LIGHT_SAMPLING_NEE) {
+ return 1.0f;
+ }
+ else
+#endif
+ return power_heuristic(nee_pdf, forward_pdf);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/osl/CMakeLists.txt b/intern/cycles/kernel/osl/CMakeLists.txt
index 6cdc7367fbb..90e16bd70d4 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}
@@ -55,7 +55,7 @@ if(APPLE)
# Disable allocation warning on macOS prior to 10.14: the OSLRenderServices
# contains member which is 64 bytes aligned (cache inside of OIIO's
# unordered_map_concurrent). This is not something what the SDK supportsm, but
- # since we take care of allocations ourselves is is OK to ignore the
+ # since we take care of allocations ourselves is OK to ignore the
# diagnostic message.
string(APPEND CMAKE_CXX_FLAGS " -faligned-allocation")
endif()
diff --git a/intern/cycles/kernel/osl/background.cpp b/intern/cycles/kernel/osl/background.cpp
index 8e497986dcc..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"
@@ -54,7 +54,7 @@ using namespace OSL;
///
class GenericBackgroundClosure : public CClosurePrimitive {
public:
- void setup(ShaderData *sd, int /* path_flag */, float3 weight)
+ void setup(ShaderData *sd, uint32_t /* path_flag */, float3 weight)
{
background_setup(sd, weight);
}
@@ -69,7 +69,7 @@ class GenericBackgroundClosure : public CClosurePrimitive {
///
class HoldoutClosure : CClosurePrimitive {
public:
- void setup(ShaderData *sd, int /* path_flag */, float3 weight)
+ void setup(ShaderData *sd, uint32_t /* path_flag */, float3 weight)
{
closure_alloc(sd, sizeof(ShaderClosure), CLOSURE_HOLDOUT_ID, weight);
sd->flag |= SD_HOLDOUT;
diff --git a/intern/cycles/kernel/osl/bsdf_diffuse_ramp.cpp b/intern/cycles/kernel/osl/bsdf_diffuse_ramp.cpp
index a2f9d3f759a..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
@@ -53,7 +52,7 @@ class DiffuseRampClosure : public CBSDFClosure {
DiffuseRampBsdf params;
Color3 colors[8];
- void setup(ShaderData *sd, int /* path_flag */, float3 weight)
+ void setup(ShaderData *sd, uint32_t /* path_flag */, float3 weight)
{
DiffuseRampBsdf *bsdf = (DiffuseRampBsdf *)bsdf_alloc_osl(
sd, sizeof(DiffuseRampBsdf), weight, &params);
diff --git a/intern/cycles/kernel/osl/bsdf_phong_ramp.cpp b/intern/cycles/kernel/osl/bsdf_phong_ramp.cpp
index 812c3b6e71b..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
@@ -52,7 +52,7 @@ class PhongRampClosure : public CBSDFClosure {
PhongRampBsdf params;
Color3 colors[8];
- void setup(ShaderData *sd, int /* path_flag */, float3 weight)
+ void setup(ShaderData *sd, uint32_t /* path_flag */, float3 weight)
{
PhongRampBsdf *bsdf = (PhongRampBsdf *)bsdf_alloc_osl(
sd, sizeof(PhongRampBsdf), weight, &params);
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 80dfbee879e..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
@@ -56,7 +56,7 @@ using namespace OSL;
///
class GenericEmissiveClosure : public CClosurePrimitive {
public:
- void setup(ShaderData *sd, int /* path_flag */, float3 weight)
+ void setup(ShaderData *sd, uint32_t /* path_flag */, float3 weight)
{
emission_setup(sd, weight);
}
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 5d968ed85e0..00000000000
--- a/intern/cycles/kernel/osl/osl_bssrdf.cpp
+++ /dev/null
@@ -1,119 +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_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, int path_flag, float3 weight)
- {
- 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, int 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 e814fcca246..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)
-CLOSURE_FLOAT3_PARAM(DiffuseClosure, params.N),
- BSDF_CLOSURE_CLASS_END(Diffuse, diffuse)
-
- BSDF_CLOSURE_CLASS_BEGIN(Translucent, translucent, DiffuseBsdf, LABEL_DIFFUSE)
- CLOSURE_FLOAT3_PARAM(TranslucentClosure, params.N),
- BSDF_CLOSURE_CLASS_END(Translucent, translucent)
-
- BSDF_CLOSURE_CLASS_BEGIN(OrenNayar, oren_nayar, OrenNayarBsdf, LABEL_DIFFUSE)
- CLOSURE_FLOAT3_PARAM(OrenNayarClosure, params.N),
- CLOSURE_FLOAT_PARAM(OrenNayarClosure, params.roughness),
- BSDF_CLOSURE_CLASS_END(OrenNayar, oren_nayar)
-
- BSDF_CLOSURE_CLASS_BEGIN(Reflection, reflection, MicrofacetBsdf, LABEL_SINGULAR)
- CLOSURE_FLOAT3_PARAM(ReflectionClosure, params.N),
- BSDF_CLOSURE_CLASS_END(Reflection, reflection)
-
- BSDF_CLOSURE_CLASS_BEGIN(Refraction, refraction, MicrofacetBsdf, LABEL_SINGULAR)
- CLOSURE_FLOAT3_PARAM(RefractionClosure, params.N),
- CLOSURE_FLOAT_PARAM(RefractionClosure, params.ior),
- BSDF_CLOSURE_CLASS_END(Refraction, refraction)
-
- BSDF_CLOSURE_CLASS_BEGIN(AshikhminVelvet, ashikhmin_velvet, VelvetBsdf, LABEL_DIFFUSE)
- CLOSURE_FLOAT3_PARAM(AshikhminVelvetClosure, params.N),
- 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)
- CLOSURE_FLOAT3_PARAM(AshikhminShirleyClosure, params.N),
- CLOSURE_FLOAT3_PARAM(AshikhminShirleyClosure, params.T),
- CLOSURE_FLOAT_PARAM(AshikhminShirleyClosure, params.alpha_x),
- CLOSURE_FLOAT_PARAM(AshikhminShirleyClosure, params.alpha_y),
- BSDF_CLOSURE_CLASS_END(AshikhminShirley, ashikhmin_shirley)
-
- BSDF_CLOSURE_CLASS_BEGIN(DiffuseToon, diffuse_toon, ToonBsdf, LABEL_DIFFUSE)
- CLOSURE_FLOAT3_PARAM(DiffuseToonClosure, params.N),
- CLOSURE_FLOAT_PARAM(DiffuseToonClosure, params.size),
- CLOSURE_FLOAT_PARAM(DiffuseToonClosure, params.smooth),
- BSDF_CLOSURE_CLASS_END(DiffuseToon, diffuse_toon)
-
- BSDF_CLOSURE_CLASS_BEGIN(GlossyToon, glossy_toon, ToonBsdf, LABEL_GLOSSY)
- CLOSURE_FLOAT3_PARAM(GlossyToonClosure, params.N),
- CLOSURE_FLOAT_PARAM(GlossyToonClosure, params.size),
- 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)
- CLOSURE_FLOAT3_PARAM(MicrofacetGGXIsotropicClosure, params.N),
- 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)
- CLOSURE_FLOAT3_PARAM(MicrofacetGGXClosure, params.N),
- CLOSURE_FLOAT3_PARAM(MicrofacetGGXClosure, params.T),
- CLOSURE_FLOAT_PARAM(MicrofacetGGXClosure, params.alpha_x),
- 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)
- CLOSURE_FLOAT3_PARAM(MicrofacetBeckmannIsotropicClosure, params.N),
- 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)
- CLOSURE_FLOAT3_PARAM(MicrofacetBeckmannClosure, params.N),
- CLOSURE_FLOAT3_PARAM(MicrofacetBeckmannClosure, params.T),
- CLOSURE_FLOAT_PARAM(MicrofacetBeckmannClosure, params.alpha_x),
- 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)
- CLOSURE_FLOAT3_PARAM(MicrofacetGGXRefractionClosure, params.N),
- CLOSURE_FLOAT_PARAM(MicrofacetGGXRefractionClosure, params.alpha_x),
- 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)
- CLOSURE_FLOAT3_PARAM(MicrofacetBeckmannRefractionClosure, params.N),
- CLOSURE_FLOAT_PARAM(MicrofacetBeckmannRefractionClosure, params.alpha_x),
- CLOSURE_FLOAT_PARAM(MicrofacetBeckmannRefractionClosure, params.ior),
- BSDF_CLOSURE_CLASS_END(MicrofacetBeckmannRefraction, microfacet_beckmann_refraction)
-
- BSDF_CLOSURE_CLASS_BEGIN(HairReflection, hair_reflection, HairBsdf, LABEL_GLOSSY)
- CLOSURE_FLOAT3_PARAM(HairReflectionClosure, params.N),
- CLOSURE_FLOAT_PARAM(HairReflectionClosure, params.roughness1),
- CLOSURE_FLOAT_PARAM(HairReflectionClosure, params.roughness2),
- CLOSURE_FLOAT3_PARAM(HairReflectionClosure, params.T),
- CLOSURE_FLOAT_PARAM(HairReflectionClosure, params.offset),
- BSDF_CLOSURE_CLASS_END(HairReflection, hair_reflection)
-
- BSDF_CLOSURE_CLASS_BEGIN(HairTransmission, hair_transmission, HairBsdf, LABEL_GLOSSY)
- CLOSURE_FLOAT3_PARAM(HairTransmissionClosure, params.N),
- CLOSURE_FLOAT_PARAM(HairTransmissionClosure, params.roughness1),
- CLOSURE_FLOAT_PARAM(HairTransmissionClosure, params.roughness2),
- CLOSURE_FLOAT3_PARAM(HairReflectionClosure, params.T),
- CLOSURE_FLOAT_PARAM(HairReflectionClosure, params.offset),
- BSDF_CLOSURE_CLASS_END(HairTransmission, hair_transmission)
-
- BSDF_CLOSURE_CLASS_BEGIN(PrincipledDiffuse,
- principled_diffuse,
- PrincipledDiffuseBsdf,
- LABEL_DIFFUSE)
- CLOSURE_FLOAT3_PARAM(PrincipledDiffuseClosure, params.N),
- CLOSURE_FLOAT_PARAM(PrincipledDiffuseClosure, params.roughness),
- BSDF_CLOSURE_CLASS_END(PrincipledDiffuse, principled_diffuse)
-
- class PrincipledSheenClosure : public CBSDFClosure {
- public:
- PrincipledSheenBsdf params;
-
- void setup(ShaderData *sd, int 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, int 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, int 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, int 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, int 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, int path_flag, int scattering)
-{
- /* caustic options */
- if ((scattering & LABEL_GLOSSY) && (path_flag & PATH_RAY_DIFFUSE)) {
- const KernelGlobals *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, int 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, int 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, int 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, int 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, int 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, int 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, int 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, int 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, int 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, int 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, int 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, int 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, int 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, int 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, int 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 e4058e3a746..00000000000
--- a/intern/cycles/kernel/osl/osl_closures.h
+++ /dev/null
@@ -1,161 +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 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, int path_flag, float3 weight) = 0;
-
- OSL::ustring label;
-};
-
-/* BSDF */
-
-class CBSDFClosure : public CClosurePrimitive {
- public:
- bool skip(const ShaderData *sd, int 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, int 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 4fc46a255a8..00000000000
--- a/intern/cycles/kernel/osl/osl_services.cpp
+++ /dev/null
@@ -1,1693 +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_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 KernelGlobals *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 KernelGlobals *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 KernelGlobals *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 KernelGlobals *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 KernelGlobals *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 KernelGlobals *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 KernelGlobals *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 KernelGlobals *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 KernelGlobals *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 KernelGlobals *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 KernelGlobals *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
- return false;
-}
-
-bool OSLRenderServices::get_background_attribute(const KernelGlobals *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;
- int f = state->path.bounce;
- 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;
- int f = state->path.diffuse_bounce;
- 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;
- int f = state->path.glossy_bounce;
- 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;
- int f = state->path.transmission_bounce;
- 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;
- int f = state->path.transparent_bounce;
- 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 KernelGlobals *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);
- const 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;
- 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;
- 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);
- const 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);
- const 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);
- const 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 KernelGlobals *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 KernelGlobals *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/osl_services.h
deleted file mode 100644
index 2a5400282b3..00000000000
--- a/intern/cycles/kernel/osl/osl_services.h
+++ /dev/null
@@ -1,329 +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_SERVICES_H__
-#define __OSL_SERVICES_H__
-
-/* OSL Render Services
- *
- * Implementation of OSL render services, to retriever matrices, attributes,
- * textures and point clouds. In principle this should only be accessing
- * kernel data, but currently we also reach back into the Scene to retrieve
- * attributes.
- */
-
-#include <OSL/oslclosure.h>
-#include <OSL/oslexec.h>
-#include <OSL/rendererservices.h>
-
-#ifdef WITH_PTEX
-class PtexCache;
-#endif
-
-CCL_NAMESPACE_BEGIN
-
-class Object;
-class Scene;
-class Shader;
-struct ShaderData;
-struct float3;
-struct KernelGlobals;
-
-/* OSL Texture Handle
- *
- * OSL texture lookups are string based. If those strings are known at compile
- * time, the OSL compiler can cache a texture handle to use instead of a string.
- *
- * By default it uses TextureSystem::TextureHandle. But since we want to support
- * different kinds of textures and color space conversions, this is our own handle
- * with additional data.
- *
- * These are stored in a concurrent hash map, because OSL can compile multiple
- * shaders in parallel. */
-
-struct OSLTextureHandle : public OIIO::RefCnt {
- enum Type { OIIO, SVM, IES, BEVEL, AO };
-
- OSLTextureHandle(Type type = OIIO, int svm_slot = -1)
- : type(type), svm_slot(svm_slot), oiio_handle(NULL), processor(NULL)
- {
- }
-
- Type type;
- int svm_slot;
- OSL::TextureSystem::TextureHandle *oiio_handle;
- ColorSpaceProcessor *processor;
-};
-
-typedef OIIO::intrusive_ptr<OSLTextureHandle> OSLTextureHandleRef;
-typedef OIIO::unordered_map_concurrent<ustring, OSLTextureHandleRef, ustringHash>
- OSLTextureHandleMap;
-
-/* OSL Render Services
- *
- * Interface for OSL to access attributes, textures and other scene data. */
-
-class OSLRenderServices : public OSL::RendererServices {
- public:
- OSLRenderServices(OSL::TextureSystem *texture_system);
- ~OSLRenderServices();
-
- bool get_matrix(OSL::ShaderGlobals *sg,
- OSL::Matrix44 &result,
- OSL::TransformationPtr xform,
- float time) override;
- bool get_inverse_matrix(OSL::ShaderGlobals *sg,
- OSL::Matrix44 &result,
- OSL::TransformationPtr xform,
- float time) override;
-
- bool get_matrix(OSL::ShaderGlobals *sg,
- OSL::Matrix44 &result,
- ustring from,
- float time) override;
- bool get_inverse_matrix(OSL::ShaderGlobals *sg,
- OSL::Matrix44 &result,
- ustring to,
- float time) override;
-
- bool get_matrix(OSL::ShaderGlobals *sg,
- OSL::Matrix44 &result,
- OSL::TransformationPtr xform) override;
- bool get_inverse_matrix(OSL::ShaderGlobals *sg,
- OSL::Matrix44 &result,
- OSL::TransformationPtr xform) override;
-
- bool get_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44 &result, ustring from) override;
- bool get_inverse_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44 &result, ustring from) override;
-
- bool get_array_attribute(OSL::ShaderGlobals *sg,
- bool derivatives,
- ustring object,
- TypeDesc type,
- ustring name,
- int index,
- void *val) override;
- bool get_attribute(OSL::ShaderGlobals *sg,
- bool derivatives,
- ustring object,
- TypeDesc type,
- ustring name,
- void *val) override;
- bool get_attribute(ShaderData *sd,
- bool derivatives,
- ustring object_name,
- TypeDesc type,
- ustring name,
- void *val);
-
- bool get_userdata(
- bool derivatives, ustring name, TypeDesc type, OSL::ShaderGlobals *sg, void *val) override;
-
- int 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) override;
-
- int pointcloud_get(OSL::ShaderGlobals *sg,
- ustring filename,
- size_t *indices,
- int count,
- ustring attr_name,
- TypeDesc attr_type,
- void *out_data) override;
-
- bool pointcloud_write(OSL::ShaderGlobals *sg,
- ustring filename,
- const OSL::Vec3 &pos,
- int nattribs,
- const ustring *names,
- const TypeDesc *types,
- const void **data) override;
-
- bool 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) override;
-
- bool getmessage(OSL::ShaderGlobals *sg,
- ustring source,
- ustring name,
- TypeDesc type,
- void *val,
- bool derivatives) override;
-
-#if OSL_LIBRARY_VERSION_CODE >= 11100
- TextureSystem::TextureHandle *get_texture_handle(ustring filename,
- OSL::ShadingContext *context) override;
-#else
- TextureSystem::TextureHandle *get_texture_handle(ustring filename) override;
-#endif
-
- bool good(TextureSystem::TextureHandle *texture_handle) override;
-
- bool texture(ustring filename,
- TextureSystem::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) override;
-
- bool 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) override;
-
- bool environment(ustring filename,
- TextureHandle *texture_handle,
- TexturePerthread *texture_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) override;
-
-#if OSL_LIBRARY_VERSION_CODE >= 11100
- bool get_texture_info(ustring filename,
- TextureHandle *texture_handle,
- TexturePerthread *texture_thread_info,
- OSL::ShadingContext *shading_context,
- int subimage,
- ustring dataname,
- TypeDesc datatype,
- void *data,
- ustring *errormessage) override;
-#else
- bool get_texture_info(OSL::ShaderGlobals *sg,
- ustring filename,
- TextureHandle *texture_handle,
- int subimage,
- ustring dataname,
- TypeDesc datatype,
- void *data) override;
-#endif
-
- static bool get_background_attribute(const KernelGlobals *kg,
- ShaderData *sd,
- ustring name,
- TypeDesc type,
- bool derivatives,
- void *val);
- static bool get_object_standard_attribute(const KernelGlobals *kg,
- ShaderData *sd,
- ustring name,
- TypeDesc type,
- bool derivatives,
- void *val);
-
- static ustring u_distance;
- static ustring u_index;
- static ustring u_world;
- static ustring u_camera;
- static ustring u_screen;
- static ustring u_raster;
- static ustring u_ndc;
- static ustring u_object_location;
- static ustring u_object_color;
- static ustring u_object_index;
- static ustring u_geom_dupli_generated;
- static ustring u_geom_dupli_uv;
- static ustring u_material_index;
- static ustring u_object_random;
- static ustring u_particle_index;
- static ustring u_particle_random;
- static ustring u_particle_age;
- static ustring u_particle_lifetime;
- static ustring u_particle_location;
- static ustring u_particle_rotation;
- static ustring u_particle_size;
- static ustring u_particle_velocity;
- static ustring u_particle_angular_velocity;
- static ustring u_geom_numpolyvertices;
- static ustring u_geom_trianglevertices;
- static ustring u_geom_polyvertices;
- static ustring u_geom_name;
- static ustring u_geom_undisplaced;
- static ustring u_is_smooth;
- static ustring u_is_curve;
- static ustring u_curve_thickness;
- static ustring u_curve_length;
- static ustring u_curve_tangent_normal;
- static ustring u_curve_random;
- static ustring u_path_ray_length;
- static ustring u_path_ray_depth;
- static ustring u_path_diffuse_depth;
- static ustring u_path_glossy_depth;
- static ustring u_path_transparent_depth;
- static ustring u_path_transmission_depth;
- static ustring u_trace;
- static ustring u_hit;
- static ustring u_hitdist;
- static ustring u_N;
- static ustring u_Ng;
- static ustring u_P;
- static ustring u_I;
- static ustring u_u;
- static ustring u_v;
- static ustring u_empty;
- static ustring u_at_bevel;
- static ustring u_at_ao;
-
- /* Texture system and texture handle map are part of the services instead of
- * globals to be shared between different render sessions. This saves memory,
- * and is required because texture handles are cached as part of the shared
- * shading system. */
- OSL::TextureSystem *texture_system;
- OSLTextureHandleMap textures;
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __OSL_SERVICES_H__ */
diff --git a/intern/cycles/kernel/osl/osl_shader.cpp b/intern/cycles/kernel/osl/osl_shader.cpp
deleted file mode 100644
index 880ef635c76..00000000000
--- a/intern/cycles/kernel/osl/osl_shader.cpp
+++ /dev/null
@@ -1,428 +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(KernelGlobals *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(KernelGlobals *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 KernelGlobals *kg,
- ShaderData *sd,
- const IntegratorStateCPU *state,
- int 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;
- sd->osl_path_state = state;
-}
-
-/* Surface */
-
-static void flatten_surface_closure_tree(ShaderData *sd,
- int 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 KernelGlobals *kg,
- const IntegratorStateCPU *state,
- ShaderData *sd,
- int 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 KernelGlobals *kg,
- const IntegratorStateCPU *state,
- ShaderData *sd,
- int 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 KernelGlobals *kg,
- const IntegratorStateCPU *state,
- ShaderData *sd,
- int 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 KernelGlobals *kg,
- const IntegratorStateCPU *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 KernelGlobals *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 f1f17b141eb..00000000000
--- a/intern/cycles/kernel/osl/osl_shader.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 __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 KernelGlobals;
-
-struct OSLGlobals;
-struct OSLShadingSystem;
-
-class OSLShader {
- public:
- /* init */
- static void register_closures(OSLShadingSystem *ss);
-
- /* per thread data */
- static void thread_init(KernelGlobals *kg, OSLGlobals *osl_globals);
- static void thread_free(KernelGlobals *kg);
-
- /* eval */
- static void eval_surface(const KernelGlobals *kg,
- const IntegratorStateCPU *state,
- ShaderData *sd,
- int path_flag);
- static void eval_background(const KernelGlobals *kg,
- const IntegratorStateCPU *state,
- ShaderData *sd,
- int path_flag);
- static void eval_volume(const KernelGlobals *kg,
- const IntegratorStateCPU *state,
- ShaderData *sd,
- int path_flag);
- static void eval_displacement(const KernelGlobals *kg,
- const IntegratorStateCPU *state,
- ShaderData *sd);
-
- /* attributes */
- static int find_attribute(const KernelGlobals *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..d79e7dfa8a5
--- /dev/null
+++ b/intern/cycles/kernel/osl/services.cpp
@@ -0,0 +1,1757 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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/pointcloud.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_is_point("geom:is_point");
+ustring OSLRenderServices::u_point_radius("geom:point_radius");
+ustring OSLRenderServices::u_point_position("geom:point_position");
+ustring OSLRenderServices::u_point_random("geom:point_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) {
+ const float *data = (const float *)attr.value.data();
+ return set_attribute_float3(make_float3(data[0], data[1], data[2]), type, derivatives, val);
+ }
+ else if (attr.type == TypeFloat2) {
+ const float *data = (const float *)attr.value.data();
+ return set_attribute_float2(make_float2(data[0], data[1]), type, derivatives, val);
+ }
+ else if (attr.type == TypeDesc::TypeFloat) {
+ const float *data = (const float *)attr.value.data();
+ return set_attribute_float(data[0], type, derivatives, val);
+ }
+ else if (attr.type == TypeRGBA || attr.type == TypeDesc::TypeFloat4) {
+ const float *data = (const float *)attr.value.data();
+ return set_attribute_float4(
+ make_float4(data[0], data[1], data[2], data[3]), 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_TRIANGLE) {
+ float3 P[3];
+
+ if (sd->type & PRIMITIVE_MOTION) {
+ motion_triangle_vertices(kg, sd->object, sd->prim, sd->time, P);
+ }
+ else {
+ triangle_vertices(kg, sd->prim, 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_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_curve_random) {
+ float f = curve_random(kg, sd);
+ return set_attribute_float(f, type, derivatives, val);
+ }
+ /* point attributes */
+ else if (name == u_is_point) {
+ float f = (sd->type & PRIMITIVE_POINT) != 0;
+ return set_attribute_float(f, type, derivatives, val);
+ }
+ else if (name == u_point_radius) {
+ float f = point_radius(kg, sd);
+ return set_attribute_float(f, type, derivatives, val);
+ }
+ else if (name == u_point_position) {
+ float3 f = point_position(kg, sd);
+ return set_attribute_float3(f, type, derivatives, val);
+ }
+ else if (name == u_point_random) {
+ float f = point_random(kg, sd);
+ return set_attribute_float(f, type, derivatives, val);
+ }
+ else if (name == u_normal_map_normal) {
+ if (sd->type & PRIMITIVE_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/services.h b/intern/cycles/kernel/osl/services.h
new file mode 100644
index 00000000000..96c71297186
--- /dev/null
+++ b/intern/cycles/kernel/osl/services.h
@@ -0,0 +1,334 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_SERVICES_H__
+#define __OSL_SERVICES_H__
+
+/* OSL Render Services
+ *
+ * Implementation of OSL render services, to retriever matrices, attributes,
+ * textures and point clouds. In principle this should only be accessing
+ * kernel data, but currently we also reach back into the Scene to retrieve
+ * attributes.
+ */
+
+#include <OSL/oslclosure.h>
+#include <OSL/oslexec.h>
+#include <OSL/rendererservices.h>
+
+#ifdef WITH_PTEX
+class PtexCache;
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+class Object;
+class Scene;
+class Shader;
+struct ShaderData;
+struct float3;
+struct KernelGlobalsCPU;
+
+/* OSL Texture Handle
+ *
+ * OSL texture lookups are string based. If those strings are known at compile
+ * time, the OSL compiler can cache a texture handle to use instead of a string.
+ *
+ * By default it uses TextureSystem::TextureHandle. But since we want to support
+ * different kinds of textures and color space conversions, this is our own handle
+ * with additional data.
+ *
+ * These are stored in a concurrent hash map, because OSL can compile multiple
+ * shaders in parallel. */
+
+struct OSLTextureHandle : public OIIO::RefCnt {
+ enum Type { OIIO, SVM, IES, BEVEL, AO };
+
+ OSLTextureHandle(Type type = OIIO, int svm_slot = -1)
+ : type(type), svm_slot(svm_slot), oiio_handle(NULL), processor(NULL)
+ {
+ }
+
+ Type type;
+ int svm_slot;
+ OSL::TextureSystem::TextureHandle *oiio_handle;
+ ColorSpaceProcessor *processor;
+};
+
+typedef OIIO::intrusive_ptr<OSLTextureHandle> OSLTextureHandleRef;
+typedef OIIO::unordered_map_concurrent<ustring, OSLTextureHandleRef, ustringHash>
+ OSLTextureHandleMap;
+
+/* OSL Render Services
+ *
+ * Interface for OSL to access attributes, textures and other scene data. */
+
+class OSLRenderServices : public OSL::RendererServices {
+ public:
+ OSLRenderServices(OSL::TextureSystem *texture_system);
+ ~OSLRenderServices();
+
+ bool get_matrix(OSL::ShaderGlobals *sg,
+ OSL::Matrix44 &result,
+ OSL::TransformationPtr xform,
+ float time) override;
+ bool get_inverse_matrix(OSL::ShaderGlobals *sg,
+ OSL::Matrix44 &result,
+ OSL::TransformationPtr xform,
+ float time) override;
+
+ bool get_matrix(OSL::ShaderGlobals *sg,
+ OSL::Matrix44 &result,
+ ustring from,
+ float time) override;
+ bool get_inverse_matrix(OSL::ShaderGlobals *sg,
+ OSL::Matrix44 &result,
+ ustring to,
+ float time) override;
+
+ bool get_matrix(OSL::ShaderGlobals *sg,
+ OSL::Matrix44 &result,
+ OSL::TransformationPtr xform) override;
+ bool get_inverse_matrix(OSL::ShaderGlobals *sg,
+ OSL::Matrix44 &result,
+ OSL::TransformationPtr xform) override;
+
+ bool get_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44 &result, ustring from) override;
+ bool get_inverse_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44 &result, ustring from) override;
+
+ bool get_array_attribute(OSL::ShaderGlobals *sg,
+ bool derivatives,
+ ustring object,
+ TypeDesc type,
+ ustring name,
+ int index,
+ void *val) override;
+ bool get_attribute(OSL::ShaderGlobals *sg,
+ bool derivatives,
+ ustring object,
+ TypeDesc type,
+ ustring name,
+ void *val) override;
+ bool get_attribute(ShaderData *sd,
+ bool derivatives,
+ ustring object_name,
+ TypeDesc type,
+ ustring name,
+ void *val);
+
+ bool get_userdata(
+ bool derivatives, ustring name, TypeDesc type, OSL::ShaderGlobals *sg, void *val) override;
+
+ int 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) override;
+
+ int pointcloud_get(OSL::ShaderGlobals *sg,
+ ustring filename,
+ size_t *indices,
+ int count,
+ ustring attr_name,
+ TypeDesc attr_type,
+ void *out_data) override;
+
+ bool pointcloud_write(OSL::ShaderGlobals *sg,
+ ustring filename,
+ const OSL::Vec3 &pos,
+ int nattribs,
+ const ustring *names,
+ const TypeDesc *types,
+ const void **data) override;
+
+ bool 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) override;
+
+ bool getmessage(OSL::ShaderGlobals *sg,
+ ustring source,
+ ustring name,
+ TypeDesc type,
+ void *val,
+ bool derivatives) override;
+
+#if OSL_LIBRARY_VERSION_CODE >= 11100
+ TextureSystem::TextureHandle *get_texture_handle(ustring filename,
+ OSL::ShadingContext *context) override;
+#else
+ TextureSystem::TextureHandle *get_texture_handle(ustring filename) override;
+#endif
+
+ bool good(TextureSystem::TextureHandle *texture_handle) override;
+
+ bool texture(ustring filename,
+ TextureSystem::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) override;
+
+ bool 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) override;
+
+ bool environment(ustring filename,
+ TextureHandle *texture_handle,
+ TexturePerthread *texture_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) override;
+
+#if OSL_LIBRARY_VERSION_CODE >= 11100
+ bool get_texture_info(ustring filename,
+ TextureHandle *texture_handle,
+ TexturePerthread *texture_thread_info,
+ OSL::ShadingContext *shading_context,
+ int subimage,
+ ustring dataname,
+ TypeDesc datatype,
+ void *data,
+ ustring *errormessage) override;
+#else
+ bool get_texture_info(OSL::ShaderGlobals *sg,
+ ustring filename,
+ TextureHandle *texture_handle,
+ int subimage,
+ ustring dataname,
+ TypeDesc datatype,
+ void *data) override;
+#endif
+
+ static bool get_background_attribute(const KernelGlobalsCPU *kg,
+ ShaderData *sd,
+ ustring name,
+ TypeDesc type,
+ bool derivatives,
+ void *val);
+ static bool get_object_standard_attribute(const KernelGlobalsCPU *kg,
+ ShaderData *sd,
+ ustring name,
+ TypeDesc type,
+ bool derivatives,
+ void *val);
+
+ static ustring u_distance;
+ static ustring u_index;
+ static ustring u_world;
+ static ustring u_camera;
+ static ustring u_screen;
+ static ustring u_raster;
+ static ustring u_ndc;
+ static ustring u_object_location;
+ static ustring u_object_color;
+ static ustring u_object_index;
+ static ustring u_geom_dupli_generated;
+ static ustring u_geom_dupli_uv;
+ static ustring u_material_index;
+ static ustring u_object_random;
+ static ustring u_particle_index;
+ static ustring u_particle_random;
+ static ustring u_particle_age;
+ static ustring u_particle_lifetime;
+ static ustring u_particle_location;
+ static ustring u_particle_rotation;
+ static ustring u_particle_size;
+ static ustring u_particle_velocity;
+ static ustring u_particle_angular_velocity;
+ static ustring u_geom_numpolyvertices;
+ static ustring u_geom_trianglevertices;
+ static ustring u_geom_polyvertices;
+ static ustring u_geom_name;
+ static ustring u_geom_undisplaced;
+ static ustring u_is_smooth;
+ static ustring u_is_curve;
+ static ustring u_curve_thickness;
+ static ustring u_curve_length;
+ static ustring u_curve_tangent_normal;
+ static ustring u_curve_random;
+ static ustring u_is_point;
+ static ustring u_point_position;
+ static ustring u_point_radius;
+ static ustring u_point_random;
+ static ustring u_normal_map_normal;
+ static ustring u_path_ray_length;
+ static ustring u_path_ray_depth;
+ static ustring u_path_diffuse_depth;
+ static ustring u_path_glossy_depth;
+ static ustring u_path_transparent_depth;
+ static ustring u_path_transmission_depth;
+ static ustring u_trace;
+ static ustring u_hit;
+ static ustring u_hitdist;
+ static ustring u_N;
+ static ustring u_Ng;
+ static ustring u_P;
+ static ustring u_I;
+ static ustring u_u;
+ static ustring u_v;
+ static ustring u_empty;
+ static ustring u_at_bevel;
+ static ustring u_at_ao;
+
+ /* Texture system and texture handle map are part of the services instead of
+ * globals to be shared between different render sessions. This saves memory,
+ * and is required because texture handles are cached as part of the shared
+ * shading system. */
+ OSL::TextureSystem *texture_system;
+ OSLTextureHandleMap textures;
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __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..ae001b34a1d
--- /dev/null
+++ b/intern/cycles/kernel/osl/shader.cpp
@@ -0,0 +1,430 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_path_state = nullptr;
+ sd->osl_shadow_path_state = (const IntegratorShadowStateCPU *)state;
+ }
+ else {
+ sd->osl_path_state = (const IntegratorStateCPU *)state;
+ sd->osl_shadow_path_state = nullptr;
+ }
+}
+
+/* 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/osl/shaders/CMakeLists.txt b/intern/cycles/kernel/osl/shaders/CMakeLists.txt
new file mode 100644
index 00000000000..16a9b1cc012
--- /dev/null
+++ b/intern/cycles/kernel/osl/shaders/CMakeLists.txt
@@ -0,0 +1,157 @@
+# 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.
+
+# OSL node shaders
+
+set(SRC_OSL
+ node_add_closure.osl
+ node_ambient_occlusion.osl
+ node_anisotropic_bsdf.osl
+ node_attribute.osl
+ node_background.osl
+ node_bevel.osl
+ node_brick_texture.osl
+ node_brightness.osl
+ node_bump.osl
+ node_camera.osl
+ node_checker_texture.osl
+ node_clamp.osl
+ node_combine_rgb.osl
+ node_combine_hsv.osl
+ node_combine_xyz.osl
+ node_convert_from_color.osl
+ node_convert_from_float.osl
+ node_convert_from_int.osl
+ node_convert_from_normal.osl
+ node_convert_from_point.osl
+ node_convert_from_vector.osl
+ node_diffuse_bsdf.osl
+ node_displacement.osl
+ node_vector_displacement.osl
+ node_emission.osl
+ node_environment_texture.osl
+ node_float_curve.osl
+ node_fresnel.osl
+ node_gamma.osl
+ node_geometry.osl
+ node_glass_bsdf.osl
+ node_glossy_bsdf.osl
+ node_gradient_texture.osl
+ node_hair_info.osl
+ node_point_info.osl
+ node_scatter_volume.osl
+ node_absorption_volume.osl
+ node_principled_volume.osl
+ node_holdout.osl
+ node_hsv.osl
+ node_ies_light.osl
+ node_image_texture.osl
+ node_invert.osl
+ node_layer_weight.osl
+ node_light_falloff.osl
+ node_light_path.osl
+ node_magic_texture.osl
+ node_map_range.osl
+ node_mapping.osl
+ node_math.osl
+ node_mix.osl
+ node_mix_closure.osl
+ node_musgrave_texture.osl
+ node_noise_texture.osl
+ node_normal.osl
+ node_normal_map.osl
+ node_object_info.osl
+ node_output_displacement.osl
+ node_output_surface.osl
+ node_output_volume.osl
+ node_particle_info.osl
+ node_refraction_bsdf.osl
+ node_rgb_curves.osl
+ node_rgb_ramp.osl
+ node_separate_rgb.osl
+ node_separate_hsv.osl
+ node_separate_xyz.osl
+ node_set_normal.osl
+ node_sky_texture.osl
+ node_subsurface_scattering.osl
+ node_tangent.osl
+ node_texture_coordinate.osl
+ node_toon_bsdf.osl
+ node_translucent_bsdf.osl
+ node_transparent_bsdf.osl
+ node_value.osl
+ node_vector_curves.osl
+ node_vector_math.osl
+ node_vector_map_range.osl
+ node_vector_rotate.osl
+ node_vector_transform.osl
+ node_velvet_bsdf.osl
+ node_vertex_color.osl
+ node_voronoi_texture.osl
+ node_voxel_texture.osl
+ node_wavelength.osl
+ node_blackbody.osl
+ node_wave_texture.osl
+ node_white_noise_texture.osl
+ node_wireframe.osl
+ node_hair_bsdf.osl
+ node_principled_hair_bsdf.osl
+ node_uv_map.osl
+ node_principled_bsdf.osl
+ node_rgb_to_bw.osl
+)
+
+# The headers that OSL ships differs per release so we can not
+# hardcode this.
+file(GLOB SRC_OSL_HEADER_DIST ${OSL_SHADER_DIR}/*.h)
+
+set(SRC_OSL_HEADERS
+ node_color.h
+ node_fresnel.h
+ node_hash.h
+ node_math.h
+ node_noise.h
+ node_ramp_util.h
+ stdcycles.h
+ ${SRC_OSL_HEADER_DIST}
+)
+
+set(SRC_OSO
+
+)
+
+# TODO, add a module to compile OSL
+foreach(_file ${SRC_OSL})
+ set(_OSL_FILE ${CMAKE_CURRENT_SOURCE_DIR}/${_file})
+ set_source_files_properties(${_file} PROPERTIES HEADER_FILE_ONLY TRUE)
+ string(REPLACE ".osl" ".oso" _OSO_FILE ${_OSL_FILE})
+ string(REPLACE ${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} _OSO_FILE ${_OSO_FILE})
+ add_custom_command(
+ OUTPUT ${_OSO_FILE}
+ COMMAND ${OSL_COMPILER} -q -O2 -I"${CMAKE_CURRENT_SOURCE_DIR}" -I"${OSL_SHADER_DIR}" -o ${_OSO_FILE} ${_OSL_FILE}
+ DEPENDS ${_OSL_FILE} ${SRC_OSL_HEADERS} ${OSL_COMPILER})
+ list(APPEND SRC_OSO
+ ${_OSO_FILE}
+ )
+
+ unset(_OSL_FILE)
+ unset(_OSO_FILE)
+endforeach()
+
+add_custom_target(cycles_osl_shaders ALL DEPENDS ${SRC_OSO} ${SRC_OSL_HEADERS} ${OSL_COMPILER} SOURCES ${SRC_OSL})
+cycles_set_solution_folder(cycles_osl_shaders)
+
+# CMAKE_CURRENT_SOURCE_DIR is already included in OSO paths
+delayed_install("" "${SRC_OSO}" ${CYCLES_INSTALL_PATH}/shader)
+delayed_install("${CMAKE_CURRENT_SOURCE_DIR}" "${SRC_OSL_HEADERS}" ${CYCLES_INSTALL_PATH}/shader)
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/osl/shaders/node_float_curve.osl b/intern/cycles/kernel/osl/shaders/node_float_curve.osl
new file mode 100644
index 00000000000..f1f05fd88a9
--- /dev/null
+++ b/intern/cycles/kernel/osl/shaders/node_float_curve.osl
@@ -0,0 +1,32 @@
+/*
+ * 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 "node_ramp_util.h"
+#include "stdcycles.h"
+
+shader node_float_curve(float ramp[] = {0.0},
+ float min_x = 0.0,
+ float max_x = 1.0,
+ float ValueIn = 0.0,
+ float Factor = 0.0,
+ output float ValueOut = 0.0)
+{
+ float c = (ValueIn - min_x) / (max_x - min_x);
+
+ ValueOut = rgb_ramp_lookup(ramp, c, 1, 1);
+
+ ValueOut = mix(ValueIn, ValueOut, Factor);
+}
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/osl/shaders/node_image_texture.osl b/intern/cycles/kernel/osl/shaders/node_image_texture.osl
new file mode 100644
index 00000000000..56fcc47a011
--- /dev/null
+++ b/intern/cycles/kernel/osl/shaders/node_image_texture.osl
@@ -0,0 +1,270 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "node_color.h"
+#include "stdcycles.h"
+
+point texco_remap_square(point co)
+{
+ return (co - point(0.5, 0.5, 0.5)) * 2.0;
+}
+
+point map_to_tube(vector dir)
+{
+ float u, v;
+ v = (dir[2] + 1.0) * 0.5;
+ float len = sqrt(dir[0] * dir[0] + dir[1] * dir[1]);
+ if (len > 0.0) {
+ u = (1.0 - (atan2(dir[0] / len, dir[1] / len) / M_PI)) * 0.5;
+ }
+ else {
+ v = u = 0.0; /* To avoid un-initialized variables. */
+ }
+ return point(u, v, 0.0);
+}
+
+point map_to_sphere(vector dir)
+{
+ float len = length(dir);
+ float v, u;
+ if (len > 0.0) {
+ if (dir[0] == 0.0 && dir[1] == 0.0) {
+ u = 0.0; /* Otherwise domain error. */
+ }
+ else {
+ u = (1.0 - atan2(dir[0], dir[1]) / M_PI) / 2.0;
+ }
+ v = 1.0 - acos(dir[2] / len) / M_PI;
+ }
+ else {
+ v = u = 0.0; /* To avoid un-initialized variables. */
+ }
+ return point(u, v, 0.0);
+}
+
+color image_texture_lookup(string filename,
+ float u,
+ float v,
+ output float Alpha,
+ int compress_as_srgb,
+ int ignore_alpha,
+ int unassociate_alpha,
+ int is_float,
+ int is_tiled,
+ string interpolation,
+ string extension)
+{
+ /* Flip the y coordinate, but preserve UDIM tiles. */
+ float flip_v;
+ if (is_tiled) {
+ float v_i = (int)v;
+ flip_v = v_i + (1.0 - (v - v_i));
+ }
+ else {
+ flip_v = 1.0 - v;
+ }
+ color rgb = (color)texture(
+ filename, u, flip_v, "wrap", extension, "interp", interpolation, "alpha", Alpha);
+
+ if (ignore_alpha) {
+ Alpha = 1.0;
+ }
+ else if (unassociate_alpha) {
+ rgb = color_unpremultiply(rgb, Alpha);
+
+ if (!is_float)
+ rgb = min(rgb, 1.0);
+ }
+
+ if (compress_as_srgb) {
+ rgb = color_srgb_to_scene_linear(rgb);
+ }
+
+ return rgb;
+}
+
+shader node_image_texture(int use_mapping = 0,
+ matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
+ point Vector = P,
+ string filename = "",
+ string projection = "flat",
+ string interpolation = "smartcubic",
+ string extension = "periodic",
+ float projection_blend = 0.0,
+ int compress_as_srgb = 0,
+ int ignore_alpha = 0,
+ int unassociate_alpha = 0,
+ int is_tiled = 0,
+ int is_float = 1,
+ output color Color = 0.0,
+ output float Alpha = 1.0)
+{
+ point p = Vector;
+
+ if (use_mapping)
+ p = transform(mapping, p);
+
+ if (projection == "flat") {
+ Color = image_texture_lookup(filename,
+ p[0],
+ p[1],
+ Alpha,
+ compress_as_srgb,
+ ignore_alpha,
+ unassociate_alpha,
+ is_float,
+ is_tiled,
+ interpolation,
+ extension);
+ }
+ else if (projection == "box") {
+ /* object space normal */
+ vector Nob = transform("world", "object", N);
+
+ /* project from direction vector to barycentric coordinates in triangles */
+ Nob = vector(fabs(Nob[0]), fabs(Nob[1]), fabs(Nob[2]));
+ Nob /= (Nob[0] + Nob[1] + Nob[2]);
+
+ /* 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. */
+
+ vector weight = vector(0.0, 0.0, 0.0);
+ float blend = projection_blend;
+ float limit = 0.5 * (1.0 + blend);
+
+ /* first test for corners with single texture */
+ if (Nob[0] > limit * (Nob[0] + Nob[1]) && Nob[0] > limit * (Nob[0] + Nob[2])) {
+ weight[0] = 1.0;
+ }
+ else if (Nob[1] > limit * (Nob[0] + Nob[1]) && Nob[1] > limit * (Nob[1] + Nob[2])) {
+ weight[1] = 1.0;
+ }
+ else if (Nob[2] > limit * (Nob[0] + Nob[2]) && Nob[2] > limit * (Nob[1] + Nob[2])) {
+ weight[2] = 1.0;
+ }
+ else if (blend > 0.0) {
+ /* in case of blending, test for mixes between two textures */
+ if (Nob[2] < (1.0 - limit) * (Nob[1] + Nob[0])) {
+ weight[0] = Nob[0] / (Nob[0] + Nob[1]);
+ weight[0] = clamp((weight[0] - 0.5 * (1.0 - blend)) / blend, 0.0, 1.0);
+ weight[1] = 1.0 - weight[0];
+ }
+ else if (Nob[0] < (1.0 - limit) * (Nob[1] + Nob[2])) {
+ weight[1] = Nob[1] / (Nob[1] + Nob[2]);
+ weight[1] = clamp((weight[1] - 0.5 * (1.0 - blend)) / blend, 0.0, 1.0);
+ weight[2] = 1.0 - weight[1];
+ }
+ else if (Nob[1] < (1.0 - limit) * (Nob[0] + Nob[2])) {
+ weight[0] = Nob[0] / (Nob[0] + Nob[2]);
+ weight[0] = clamp((weight[0] - 0.5 * (1.0 - blend)) / blend, 0.0, 1.0);
+ weight[2] = 1.0 - weight[0];
+ }
+ else {
+ /* last case, we have a mix between three */
+ weight[0] = ((2.0 - limit) * Nob[0] + (limit - 1.0)) / (2.0 * limit - 1.0);
+ weight[1] = ((2.0 - limit) * Nob[1] + (limit - 1.0)) / (2.0 * limit - 1.0);
+ weight[2] = ((2.0 - limit) * Nob[2] + (limit - 1.0)) / (2.0 * limit - 1.0);
+ }
+ }
+ else {
+ /* Desperate mode, no valid choice anyway, fallback to one side.*/
+ weight[0] = 1.0;
+ }
+
+ Color = color(0.0, 0.0, 0.0);
+ Alpha = 0.0;
+
+ float tmp_alpha;
+
+ if (weight[0] > 0.0) {
+ Color += weight[0] * image_texture_lookup(filename,
+ p[1],
+ p[2],
+ tmp_alpha,
+ compress_as_srgb,
+ ignore_alpha,
+ unassociate_alpha,
+ is_float,
+ 0,
+ interpolation,
+ extension);
+ Alpha += weight[0] * tmp_alpha;
+ }
+ if (weight[1] > 0.0) {
+ Color += weight[1] * image_texture_lookup(filename,
+ p[0],
+ p[2],
+ tmp_alpha,
+ compress_as_srgb,
+ ignore_alpha,
+ unassociate_alpha,
+ is_float,
+ 0,
+ interpolation,
+ extension);
+ Alpha += weight[1] * tmp_alpha;
+ }
+ if (weight[2] > 0.0) {
+ Color += weight[2] * image_texture_lookup(filename,
+ p[1],
+ p[0],
+ tmp_alpha,
+ compress_as_srgb,
+ ignore_alpha,
+ unassociate_alpha,
+ is_float,
+ 0,
+ interpolation,
+ extension);
+ Alpha += weight[2] * tmp_alpha;
+ }
+ }
+ else if (projection == "sphere") {
+ point projected = map_to_sphere(texco_remap_square(p));
+ Color = image_texture_lookup(filename,
+ projected[0],
+ projected[1],
+ Alpha,
+ compress_as_srgb,
+ ignore_alpha,
+ unassociate_alpha,
+ is_float,
+ 0,
+ interpolation,
+ extension);
+ }
+ else if (projection == "tube") {
+ point projected = map_to_tube(texco_remap_square(p));
+ Color = image_texture_lookup(filename,
+ projected[0],
+ projected[1],
+ Alpha,
+ compress_as_srgb,
+ ignore_alpha,
+ unassociate_alpha,
+ is_float,
+ 0,
+ interpolation,
+ extension);
+ }
+}
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/osl/shaders/node_magic_texture.osl b/intern/cycles/kernel/osl/shaders/node_magic_texture.osl
new file mode 100644
index 00000000000..0ed83aae3b8
--- /dev/null
+++ b/intern/cycles/kernel/osl/shaders/node_magic_texture.osl
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "stdcycles.h"
+
+/* Magic */
+color magic(point p, float scale, int n, float distortion)
+{
+ float dist = distortion;
+
+ float a = mod(p.x * scale, M_2PI);
+ float b = mod(p.y * scale, M_2PI);
+ float c = mod(p.z * scale, M_2PI);
+
+ float x = sin((a + b + c) * 5.0);
+ float y = cos((-a + b - c) * 5.0);
+ float z = -cos((-a - b + c) * 5.0);
+
+ if (n > 0) {
+ x *= dist;
+ y *= dist;
+ z *= dist;
+ y = -cos(x - y + z);
+ y *= dist;
+
+ if (n > 1) {
+ x = cos(x - y - z);
+ x *= dist;
+
+ if (n > 2) {
+ z = sin(-x - y - z);
+ z *= dist;
+
+ if (n > 3) {
+ x = -cos(-x + y - z);
+ x *= dist;
+
+ if (n > 4) {
+ y = -sin(-x + y + z);
+ y *= dist;
+
+ if (n > 5) {
+ y = -cos(-x + y + z);
+ y *= dist;
+
+ if (n > 6) {
+ x = cos(x + y + z);
+ x *= dist;
+
+ if (n > 7) {
+ z = sin(x + y - z);
+ z *= dist;
+
+ if (n > 8) {
+ x = -cos(-x - y + z);
+ x *= dist;
+
+ if (n > 9) {
+ y = -sin(x - y + z);
+ y *= dist;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (dist != 0.0) {
+ dist *= 2.0;
+ x /= dist;
+ y /= dist;
+ z /= dist;
+ }
+
+ return color(0.5 - x, 0.5 - y, 0.5 - z);
+}
+
+shader node_magic_texture(int use_mapping = 0,
+ matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
+ int depth = 2,
+ float Distortion = 5.0,
+ float Scale = 5.0,
+ point Vector = P,
+ output float Fac = 0.0,
+ output color Color = 0.0)
+{
+ point p = Vector;
+
+ if (use_mapping)
+ p = transform(mapping, p);
+
+ Color = magic(p, Scale, depth, Distortion);
+ Fac = (Color[0] + Color[1] + Color[2]) * (1.0 / 3.0);
+}
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/osl/shaders/node_musgrave_texture.osl b/intern/cycles/kernel/osl/shaders/node_musgrave_texture.osl
new file mode 100644
index 00000000000..6a688d654c9
--- /dev/null
+++ b/intern/cycles/kernel/osl/shaders/node_musgrave_texture.osl
@@ -0,0 +1,803 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "node_noise.h"
+#include "stdcycles.h"
+#include "vector2.h"
+#include "vector4.h"
+
+#define vector3 point
+
+/* 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"
+ */
+
+float noise_musgrave_fBm_1d(float co, float H, float lacunarity, float octaves)
+{
+ float p = co;
+ float value = 0.0;
+ float pwr = 1.0;
+ float pwHL = pow(lacunarity, -H);
+
+ for (int i = 0; i < (int)octaves; i++) {
+ value += safe_snoise(p) * pwr;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value += rmd * safe_snoise(p) * pwr;
+ }
+
+ return value;
+}
+
+/* 1D Musgrave Multifractal
+ *
+ * H: highest fractal dimension
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ */
+
+float noise_musgrave_multi_fractal_1d(float co, float H, float lacunarity, float octaves)
+{
+ float p = co;
+ float value = 1.0;
+ float pwr = 1.0;
+ float pwHL = pow(lacunarity, -H);
+
+ for (int i = 0; i < (int)octaves; i++) {
+ value *= (pwr * safe_snoise(p) + 1.0);
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value *= (rmd * pwr * safe_snoise(p) + 1.0); /* 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'
+ */
+
+float noise_musgrave_hetero_terrain_1d(
+ float co, float H, float lacunarity, float octaves, float offset)
+{
+ float p = co;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ /* first unscaled octave of function; later octaves are scaled */
+ float value = offset + safe_snoise(p);
+ p *= lacunarity;
+
+ for (int i = 1; i < (int)octaves; i++) {
+ float increment = (safe_snoise(p) + offset) * pwr * value;
+ value += increment;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ float increment = (safe_snoise(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'
+ */
+
+float noise_musgrave_hybrid_multi_fractal_1d(
+ float co, float H, float lacunarity, float octaves, float offset, float gain)
+{
+ float p = co;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ float value = safe_snoise(p) + offset;
+ float weight = gain * value;
+ p *= lacunarity;
+
+ for (int i = 1; (weight > 0.001) && (i < (int)octaves); i++) {
+ if (weight > 1.0) {
+ weight = 1.0;
+ }
+
+ float signal = (safe_snoise(p) + offset) * pwr;
+ pwr *= pwHL;
+ value += weight * signal;
+ weight *= gain * signal;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value += rmd * ((safe_snoise(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'
+ */
+
+float noise_musgrave_ridged_multi_fractal_1d(
+ float co, float H, float lacunarity, float octaves, float offset, float gain)
+{
+ float p = co;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ float signal = offset - fabs(safe_snoise(p));
+ signal *= signal;
+ float value = signal;
+ float weight = 1.0;
+
+ for (int i = 1; i < (int)octaves; i++) {
+ p *= lacunarity;
+ weight = clamp(signal * gain, 0.0, 1.0);
+ signal = offset - fabs(safe_snoise(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"
+ */
+
+float noise_musgrave_fBm_2d(vector2 co, float H, float lacunarity, float octaves)
+{
+ vector2 p = co;
+ float value = 0.0;
+ float pwr = 1.0;
+ float pwHL = pow(lacunarity, -H);
+
+ for (int i = 0; i < (int)octaves; i++) {
+ value += safe_snoise(p) * pwr;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value += rmd * safe_snoise(p) * pwr;
+ }
+
+ return value;
+}
+
+/* 2D Musgrave Multifractal
+ *
+ * H: highest fractal dimension
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ */
+
+float noise_musgrave_multi_fractal_2d(vector2 co, float H, float lacunarity, float octaves)
+{
+ vector2 p = co;
+ float value = 1.0;
+ float pwr = 1.0;
+ float pwHL = pow(lacunarity, -H);
+
+ for (int i = 0; i < (int)octaves; i++) {
+ value *= (pwr * safe_snoise(p) + 1.0);
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value *= (rmd * pwr * safe_snoise(p) + 1.0); /* 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'
+ */
+
+float noise_musgrave_hetero_terrain_2d(
+ vector2 co, float H, float lacunarity, float octaves, float offset)
+{
+ vector2 p = co;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ /* first unscaled octave of function; later octaves are scaled */
+ float value = offset + safe_snoise(p);
+ p *= lacunarity;
+
+ for (int i = 1; i < (int)octaves; i++) {
+ float increment = (safe_snoise(p) + offset) * pwr * value;
+ value += increment;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ float increment = (safe_snoise(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'
+ */
+
+float noise_musgrave_hybrid_multi_fractal_2d(
+ vector2 co, float H, float lacunarity, float octaves, float offset, float gain)
+{
+ vector2 p = co;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ float value = safe_snoise(p) + offset;
+ float weight = gain * value;
+ p *= lacunarity;
+
+ for (int i = 1; (weight > 0.001) && (i < (int)octaves); i++) {
+ if (weight > 1.0) {
+ weight = 1.0;
+ }
+
+ float signal = (safe_snoise(p) + offset) * pwr;
+ pwr *= pwHL;
+ value += weight * signal;
+ weight *= gain * signal;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value += rmd * ((safe_snoise(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'
+ */
+
+float noise_musgrave_ridged_multi_fractal_2d(
+ vector2 co, float H, float lacunarity, float octaves, float offset, float gain)
+{
+ vector2 p = co;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ float signal = offset - fabs(safe_snoise(p));
+ signal *= signal;
+ float value = signal;
+ float weight = 1.0;
+
+ for (int i = 1; i < (int)octaves; i++) {
+ p *= lacunarity;
+ weight = clamp(signal * gain, 0.0, 1.0);
+ signal = offset - fabs(safe_snoise(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"
+ */
+
+float noise_musgrave_fBm_3d(vector3 co, float H, float lacunarity, float octaves)
+{
+ vector3 p = co;
+ float value = 0.0;
+ float pwr = 1.0;
+ float pwHL = pow(lacunarity, -H);
+
+ for (int i = 0; i < (int)octaves; i++) {
+ value += safe_snoise(p) * pwr;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value += rmd * safe_snoise(p) * pwr;
+ }
+
+ return value;
+}
+
+/* 3D Musgrave Multifractal
+ *
+ * H: highest fractal dimension
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ */
+
+float noise_musgrave_multi_fractal_3d(vector3 co, float H, float lacunarity, float octaves)
+{
+ vector3 p = co;
+ float value = 1.0;
+ float pwr = 1.0;
+ float pwHL = pow(lacunarity, -H);
+
+ for (int i = 0; i < (int)octaves; i++) {
+ value *= (pwr * safe_snoise(p) + 1.0);
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value *= (rmd * pwr * safe_snoise(p) + 1.0); /* 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'
+ */
+
+float noise_musgrave_hetero_terrain_3d(
+ vector3 co, float H, float lacunarity, float octaves, float offset)
+{
+ vector3 p = co;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ /* first unscaled octave of function; later octaves are scaled */
+ float value = offset + safe_snoise(p);
+ p *= lacunarity;
+
+ for (int i = 1; i < (int)octaves; i++) {
+ float increment = (safe_snoise(p) + offset) * pwr * value;
+ value += increment;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ float increment = (safe_snoise(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'
+ */
+
+float noise_musgrave_hybrid_multi_fractal_3d(
+ vector3 co, float H, float lacunarity, float octaves, float offset, float gain)
+{
+ vector3 p = co;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ float value = safe_snoise(p) + offset;
+ float weight = gain * value;
+ p *= lacunarity;
+
+ for (int i = 1; (weight > 0.001) && (i < (int)octaves); i++) {
+ if (weight > 1.0) {
+ weight = 1.0;
+ }
+
+ float signal = (safe_snoise(p) + offset) * pwr;
+ pwr *= pwHL;
+ value += weight * signal;
+ weight *= gain * signal;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value += rmd * ((safe_snoise(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'
+ */
+
+float noise_musgrave_ridged_multi_fractal_3d(
+ vector3 co, float H, float lacunarity, float octaves, float offset, float gain)
+{
+ vector3 p = co;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ float signal = offset - fabs(safe_snoise(p));
+ signal *= signal;
+ float value = signal;
+ float weight = 1.0;
+
+ for (int i = 1; i < (int)octaves; i++) {
+ p *= lacunarity;
+ weight = clamp(signal * gain, 0.0, 1.0);
+ signal = offset - fabs(safe_snoise(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"
+ */
+
+float noise_musgrave_fBm_4d(vector4 co, float H, float lacunarity, float octaves)
+{
+ vector4 p = co;
+ float value = 0.0;
+ float pwr = 1.0;
+ float pwHL = pow(lacunarity, -H);
+
+ for (int i = 0; i < (int)octaves; i++) {
+ value += safe_snoise(p) * pwr;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value += rmd * safe_snoise(p) * pwr;
+ }
+
+ return value;
+}
+
+/* 4D Musgrave Multifractal
+ *
+ * H: highest fractal dimension
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ */
+
+float noise_musgrave_multi_fractal_4d(vector4 co, float H, float lacunarity, float octaves)
+{
+ vector4 p = co;
+ float value = 1.0;
+ float pwr = 1.0;
+ float pwHL = pow(lacunarity, -H);
+
+ for (int i = 0; i < (int)octaves; i++) {
+ value *= (pwr * safe_snoise(p) + 1.0);
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value *= (rmd * pwr * safe_snoise(p) + 1.0); /* 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'
+ */
+
+float noise_musgrave_hetero_terrain_4d(
+ vector4 co, float H, float lacunarity, float octaves, float offset)
+{
+ vector4 p = co;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ /* first unscaled octave of function; later octaves are scaled */
+ float value = offset + safe_snoise(p);
+ p *= lacunarity;
+
+ for (int i = 1; i < (int)octaves; i++) {
+ float increment = (safe_snoise(p) + offset) * pwr * value;
+ value += increment;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ float increment = (safe_snoise(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'
+ */
+
+float noise_musgrave_hybrid_multi_fractal_4d(
+ vector4 co, float H, float lacunarity, float octaves, float offset, float gain)
+{
+ vector4 p = co;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ float value = safe_snoise(p) + offset;
+ float weight = gain * value;
+ p *= lacunarity;
+
+ for (int i = 1; (weight > 0.001) && (i < (int)octaves); i++) {
+ if (weight > 1.0) {
+ weight = 1.0;
+ }
+
+ float signal = (safe_snoise(p) + offset) * pwr;
+ pwr *= pwHL;
+ value += weight * signal;
+ weight *= gain * signal;
+ p *= lacunarity;
+ }
+
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value += rmd * ((safe_snoise(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'
+ */
+
+float noise_musgrave_ridged_multi_fractal_4d(
+ vector4 co, float H, float lacunarity, float octaves, float offset, float gain)
+{
+ vector4 p = co;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ float signal = offset - fabs(safe_snoise(p));
+ signal *= signal;
+ float value = signal;
+ float weight = 1.0;
+
+ for (int i = 1; i < (int)octaves; i++) {
+ p *= lacunarity;
+ weight = clamp(signal * gain, 0.0, 1.0);
+ signal = offset - fabs(safe_snoise(p));
+ signal *= signal;
+ signal *= weight;
+ value += signal * pwr;
+ pwr *= pwHL;
+ }
+
+ return value;
+}
+
+shader node_musgrave_texture(
+ int use_mapping = 0,
+ matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
+ string musgrave_type = "fBM",
+ string dimensions = "3D",
+ point Vector = P,
+ float W = 0.0,
+ float Dimension = 2.0,
+ float Scale = 5.0,
+ float Detail = 2.0,
+ float Lacunarity = 2.0,
+ float Offset = 0.0,
+ float Gain = 1.0,
+ output float Fac = 0.0)
+{
+ float dimension = max(Dimension, 1e-5);
+ float octaves = clamp(Detail, 0.0, 15.0);
+ float lacunarity = max(Lacunarity, 1e-5);
+
+ vector3 s = Vector;
+
+ if (use_mapping)
+ s = transform(mapping, s);
+
+ if (dimensions == "1D") {
+ float p = W * Scale;
+ if (musgrave_type == "multifractal") {
+ Fac = noise_musgrave_multi_fractal_1d(p, dimension, lacunarity, octaves);
+ }
+ else if (musgrave_type == "fBM") {
+ Fac = noise_musgrave_fBm_1d(p, dimension, lacunarity, octaves);
+ }
+ else if (musgrave_type == "hybrid_multifractal") {
+ Fac = noise_musgrave_hybrid_multi_fractal_1d(
+ p, dimension, lacunarity, octaves, Offset, Gain);
+ }
+ else if (musgrave_type == "ridged_multifractal") {
+ Fac = noise_musgrave_ridged_multi_fractal_1d(
+ p, dimension, lacunarity, octaves, Offset, Gain);
+ }
+ else if (musgrave_type == "hetero_terrain") {
+ Fac = noise_musgrave_hetero_terrain_1d(p, dimension, lacunarity, octaves, Offset);
+ }
+ else {
+ Fac = 0.0;
+ }
+ }
+ else if (dimensions == "2D") {
+ vector2 p = vector2(s[0], s[1]) * Scale;
+ if (musgrave_type == "multifractal") {
+ Fac = noise_musgrave_multi_fractal_2d(p, dimension, lacunarity, octaves);
+ }
+ else if (musgrave_type == "fBM") {
+ Fac = noise_musgrave_fBm_2d(p, dimension, lacunarity, octaves);
+ }
+ else if (musgrave_type == "hybrid_multifractal") {
+ Fac = noise_musgrave_hybrid_multi_fractal_2d(
+ p, dimension, lacunarity, octaves, Offset, Gain);
+ }
+ else if (musgrave_type == "ridged_multifractal") {
+ Fac = noise_musgrave_ridged_multi_fractal_2d(
+ p, dimension, lacunarity, octaves, Offset, Gain);
+ }
+ else if (musgrave_type == "hetero_terrain") {
+ Fac = noise_musgrave_hetero_terrain_2d(p, dimension, lacunarity, octaves, Offset);
+ }
+ else {
+ Fac = 0.0;
+ }
+ }
+ else if (dimensions == "3D") {
+ vector3 p = s * Scale;
+ if (musgrave_type == "multifractal") {
+ Fac = noise_musgrave_multi_fractal_3d(p, dimension, lacunarity, octaves);
+ }
+ else if (musgrave_type == "fBM") {
+ Fac = noise_musgrave_fBm_3d(p, dimension, lacunarity, octaves);
+ }
+ else if (musgrave_type == "hybrid_multifractal") {
+ Fac = noise_musgrave_hybrid_multi_fractal_3d(
+ p, dimension, lacunarity, octaves, Offset, Gain);
+ }
+ else if (musgrave_type == "ridged_multifractal") {
+ Fac = noise_musgrave_ridged_multi_fractal_3d(
+ p, dimension, lacunarity, octaves, Offset, Gain);
+ }
+ else if (musgrave_type == "hetero_terrain") {
+ Fac = noise_musgrave_hetero_terrain_3d(p, dimension, lacunarity, octaves, Offset);
+ }
+ else {
+ Fac = 0.0;
+ }
+ }
+ else if (dimensions == "4D") {
+ vector4 p = vector4(s[0], s[1], s[2], W) * Scale;
+ if (musgrave_type == "multifractal") {
+ Fac = noise_musgrave_multi_fractal_4d(p, dimension, lacunarity, octaves);
+ }
+ else if (musgrave_type == "fBM") {
+ Fac = noise_musgrave_fBm_4d(p, dimension, lacunarity, octaves);
+ }
+ else if (musgrave_type == "hybrid_multifractal") {
+ Fac = noise_musgrave_hybrid_multi_fractal_4d(
+ p, dimension, lacunarity, octaves, Offset, Gain);
+ }
+ else if (musgrave_type == "ridged_multifractal") {
+ Fac = noise_musgrave_ridged_multi_fractal_4d(
+ p, dimension, lacunarity, octaves, Offset, Gain);
+ }
+ else if (musgrave_type == "hetero_terrain") {
+ Fac = noise_musgrave_hetero_terrain_4d(p, dimension, lacunarity, octaves, Offset);
+ }
+ else {
+ Fac = 0.0;
+ }
+ }
+ else {
+ Fac = 0.0;
+ }
+}
diff --git a/intern/cycles/kernel/osl/shaders/node_noise.h b/intern/cycles/kernel/osl/shaders/node_noise.h
new file mode 100644
index 00000000000..e8a71032171
--- /dev/null
+++ b/intern/cycles/kernel/osl/shaders/node_noise.h
@@ -0,0 +1,202 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "vector2.h"
+#include "vector4.h"
+
+#define vector3 point
+
+float safe_noise(float p)
+{
+ float f = noise("noise", p);
+ if (isinf(f))
+ return 0.5;
+ return f;
+}
+
+float safe_noise(vector2 p)
+{
+ float f = noise("noise", p.x, p.y);
+ if (isinf(f))
+ return 0.5;
+ return f;
+}
+
+float safe_noise(vector3 p)
+{
+ float f = noise("noise", p);
+ if (isinf(f))
+ return 0.5;
+ return f;
+}
+
+float safe_noise(vector4 p)
+{
+ float f = noise("noise", vector3(p.x, p.y, p.z), p.w);
+ if (isinf(f))
+ return 0.5;
+ return f;
+}
+
+float safe_snoise(float p)
+{
+ float f = noise("snoise", p);
+ if (isinf(f))
+ return 0.0;
+ return f;
+}
+
+float safe_snoise(vector2 p)
+{
+ float f = noise("snoise", p.x, p.y);
+ if (isinf(f))
+ return 0.0;
+ return f;
+}
+
+float safe_snoise(vector3 p)
+{
+ float f = noise("snoise", p);
+ if (isinf(f))
+ return 0.0;
+ return f;
+}
+
+float safe_snoise(vector4 p)
+{
+ float f = noise("snoise", vector3(p.x, p.y, p.z), p.w);
+ if (isinf(f))
+ return 0.0;
+ return f;
+}
+
+/* The fractal_noise functions are all exactly the same except for the input type. */
+float fractal_noise(float p, float details, float roughness)
+{
+ float fscale = 1.0;
+ float amp = 1.0;
+ float maxamp = 0.0;
+ float sum = 0.0;
+ float octaves = clamp(details, 0.0, 15.0);
+ int n = (int)octaves;
+ for (int i = 0; i <= n; i++) {
+ float t = safe_noise(fscale * p);
+ sum += t * amp;
+ maxamp += amp;
+ amp *= clamp(roughness, 0.0, 1.0);
+ fscale *= 2.0;
+ }
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ float t = safe_noise(fscale * p);
+ float sum2 = sum + t * amp;
+ sum /= maxamp;
+ sum2 /= maxamp + amp;
+ return (1.0 - rmd) * sum + rmd * sum2;
+ }
+ else {
+ return sum / maxamp;
+ }
+}
+
+/* The fractal_noise functions are all exactly the same except for the input type. */
+float fractal_noise(vector2 p, float details, float roughness)
+{
+ float fscale = 1.0;
+ float amp = 1.0;
+ float maxamp = 0.0;
+ float sum = 0.0;
+ float octaves = clamp(details, 0.0, 15.0);
+ int n = (int)octaves;
+ for (int i = 0; i <= n; i++) {
+ float t = safe_noise(fscale * p);
+ sum += t * amp;
+ maxamp += amp;
+ amp *= clamp(roughness, 0.0, 1.0);
+ fscale *= 2.0;
+ }
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ float t = safe_noise(fscale * p);
+ float sum2 = sum + t * amp;
+ sum /= maxamp;
+ sum2 /= maxamp + amp;
+ return (1.0 - rmd) * sum + rmd * sum2;
+ }
+ else {
+ return sum / maxamp;
+ }
+}
+
+/* The fractal_noise functions are all exactly the same except for the input type. */
+float fractal_noise(vector3 p, float details, float roughness)
+{
+ float fscale = 1.0;
+ float amp = 1.0;
+ float maxamp = 0.0;
+ float sum = 0.0;
+ float octaves = clamp(details, 0.0, 15.0);
+ int n = (int)octaves;
+ for (int i = 0; i <= n; i++) {
+ float t = safe_noise(fscale * p);
+ sum += t * amp;
+ maxamp += amp;
+ amp *= clamp(roughness, 0.0, 1.0);
+ fscale *= 2.0;
+ }
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ float t = safe_noise(fscale * p);
+ float sum2 = sum + t * amp;
+ sum /= maxamp;
+ sum2 /= maxamp + amp;
+ return (1.0 - rmd) * sum + rmd * sum2;
+ }
+ else {
+ return sum / maxamp;
+ }
+}
+
+/* The fractal_noise functions are all exactly the same except for the input type. */
+float fractal_noise(vector4 p, float details, float roughness)
+{
+ float fscale = 1.0;
+ float amp = 1.0;
+ float maxamp = 0.0;
+ float sum = 0.0;
+ float octaves = clamp(details, 0.0, 15.0);
+ int n = (int)octaves;
+ for (int i = 0; i <= n; i++) {
+ float t = safe_noise(fscale * p);
+ sum += t * amp;
+ maxamp += amp;
+ amp *= clamp(roughness, 0.0, 1.0);
+ fscale *= 2.0;
+ }
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ float t = safe_noise(fscale * p);
+ float sum2 = sum + t * amp;
+ sum /= maxamp;
+ sum2 /= maxamp + amp;
+ return (1.0 - rmd) * sum + rmd * sum2;
+ }
+ else {
+ return sum / maxamp;
+ }
+}
+
+#undef vector3
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/osl/shaders/node_normal_map.osl b/intern/cycles/kernel/osl/shaders/node_normal_map.osl
new file mode 100644
index 00000000000..9f365180eae
--- /dev/null
+++ b/intern/cycles/kernel/osl/shaders/node_normal_map.osl
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "stdcycles.h"
+
+shader node_normal_map(normal NormalIn = N,
+ float Strength = 1.0,
+ color Color = color(0.5, 0.5, 1.0),
+ string space = "tangent",
+ string attr_name = "geom:tangent",
+ string attr_sign_name = "geom:tangent_sign",
+ output normal Normal = NormalIn)
+{
+ color mcolor = 2.0 * color(Color[0] - 0.5, Color[1] - 0.5, Color[2] - 0.5);
+ int is_backfacing = backfacing();
+
+ if (space == "tangent") {
+ vector tangent;
+ vector ninterp;
+ float tangent_sign;
+ float is_smooth = 0.0;
+
+ getattribute("geom:is_smooth", is_smooth);
+ if (!is_smooth) {
+ ninterp = normalize(transform("world", "object", Ng));
+
+ /* the normal is already inverted, which is too soon for the math here */
+ if (is_backfacing) {
+ ninterp = -ninterp;
+ }
+ }
+
+ // get _unnormalized_ interpolated normal and tangent
+ if (getattribute(attr_name, tangent) && getattribute(attr_sign_name, tangent_sign) &&
+ (!is_smooth || getattribute("geom:normal_map_normal", ninterp))) {
+ // apply normal map
+ vector B = tangent_sign * cross(ninterp, tangent);
+ Normal = normalize(mcolor[0] * tangent + mcolor[1] * B + mcolor[2] * ninterp);
+
+ // transform to world space
+ Normal = normalize(transform("object", "world", Normal));
+ }
+ else {
+ Normal = normal(0, 0, 0);
+ }
+ }
+ else if (space == "object") {
+ Normal = normalize(transform("object", "world", vector(mcolor)));
+ }
+ else if (space == "world") {
+ Normal = normalize(vector(mcolor));
+ }
+ else if (space == "blender_object") {
+ /* strange blender convention */
+ mcolor[1] = -mcolor[1];
+ mcolor[2] = -mcolor[2];
+
+ Normal = normalize(transform("object", "world", vector(mcolor)));
+ }
+ else if (space == "blender_world") {
+ /* strange blender convention */
+ mcolor[1] = -mcolor[1];
+ mcolor[2] = -mcolor[2];
+
+ Normal = normalize(vector(mcolor));
+ }
+
+ /* invert normal for backfacing polygons */
+ if (is_backfacing) {
+ Normal = -Normal;
+ }
+
+ if (Strength != 1.0)
+ Normal = normalize(NormalIn + (Normal - NormalIn) * max(Strength, 0.0));
+}
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/osl/shaders/node_point_info.osl b/intern/cycles/kernel/osl/shaders/node_point_info.osl
new file mode 100644
index 00000000000..58d8acbf269
--- /dev/null
+++ b/intern/cycles/kernel/osl/shaders/node_point_info.osl
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2011-2022 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "stdcycles.h"
+
+shader node_point_info(output point Position = point(0.0, 0.0, 0.0),
+ output float Radius = 0.0,
+ output float Random = 0.0)
+{
+ getattribute("geom:point_position", Position);
+ getattribute("geom:point_radius", Radius);
+ getattribute("geom:point_random", Random);
+}
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/osl/shaders/node_vector_map_range.osl b/intern/cycles/kernel/osl/shaders/node_vector_map_range.osl
new file mode 100644
index 00000000000..1a59691fc45
--- /dev/null
+++ b/intern/cycles/kernel/osl/shaders/node_vector_map_range.osl
@@ -0,0 +1,74 @@
+/*
+ * 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 "stdcycles.h"
+
+float safe_divide(float a, float b)
+{
+ return (b != 0.0) ? a / b : 0.0;
+}
+
+point safe_divide(point a, point b)
+{
+ return point(safe_divide(a.x, b.x), safe_divide(a.y, b.y), safe_divide(a.z, b.z));
+}
+
+shader node_vector_map_range(string range_type = "linear",
+ int use_clamp = 0,
+ point VectorIn = point(1.0, 1.0, 1.0),
+ point From_Min_FLOAT3 = point(0.0, 0.0, 0.0),
+ point From_Max_FLOAT3 = point(1.0, 1.0, 1.0),
+ point To_Min_FLOAT3 = point(0.0, 0.0, 0.0),
+ point To_Max_FLOAT3 = point(1.0, 1.0, 1.0),
+ point Steps_FLOAT3 = point(4.0, 4.0, 4.0),
+ output point VectorOut = point(0.0, 0.0, 0.0))
+{
+ point factor = VectorIn;
+ point from_min = From_Min_FLOAT3;
+ point from_max = From_Max_FLOAT3;
+ point to_min = To_Min_FLOAT3;
+ point to_max = To_Max_FLOAT3;
+ point steps = Steps_FLOAT3;
+
+ if (range_type == "stepped") {
+ factor = safe_divide((factor - from_min), (from_max - from_min));
+ factor = point((steps.x > 0.0) ? floor(factor.x * (steps.x + 1.0)) / steps.x : 0.0,
+ (steps.y > 0.0) ? floor(factor.y * (steps.y + 1.0)) / steps.y : 0.0,
+ (steps.z > 0.0) ? floor(factor.z * (steps.z + 1.0)) / steps.z : 0.0);
+ }
+ else if (range_type == "smoothstep") {
+ factor = safe_divide((factor - from_min), (from_max - from_min));
+ factor = clamp(factor, 0.0, 1.0);
+ factor = (3.0 - 2.0 * factor) * (factor * factor);
+ }
+ else if (range_type == "smootherstep") {
+ factor = safe_divide((factor - from_min), (from_max - from_min));
+ factor = clamp(factor, 0.0, 1.0);
+ factor = factor * factor * factor * (factor * (factor * 6.0 - 15.0) + 10.0);
+ }
+ else {
+ factor = safe_divide((factor - from_min), (from_max - from_min));
+ }
+ VectorOut = to_min + factor * (to_max - to_min);
+ if (use_clamp > 0) {
+ VectorOut.x = (to_min.x > to_max.x) ? clamp(VectorOut.x, to_max.x, to_min.x) :
+ clamp(VectorOut.x, to_min.x, to_max.x);
+ VectorOut.y = (to_min.y > to_max.y) ? clamp(VectorOut.y, to_max.y, to_min.y) :
+ clamp(VectorOut.y, to_min.y, to_max.y);
+ VectorOut.z = (to_min.z > to_max.z) ? clamp(VectorOut.z, to_max.z, to_min.z) :
+ clamp(VectorOut.z, to_min.z, to_max.z);
+ }
+}
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..e8c4915813e
--- /dev/null
+++ b/intern/cycles/kernel/sample/lcg.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 */
+
+/* This is templated to handle multiple address spaces on Metal. */
+template<class T> ccl_device uint lcg_step_uint(T rng)
+{
+ /* implicit mod 2^32 */
+ *rng = (1103515245 * (*rng) + 12345);
+ return *rng;
+}
+
+/* This is templated to handle multiple address spaces on Metal. */
+template<class T> ccl_device float lcg_step_float(T 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..adc8493badd
--- /dev/null
+++ b/intern/cycles/kernel/sample/pattern.h
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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. */
+ return popcount(uint(sample) & 0xaaaaaaaa) & 1;
+ }
+ 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/shaders/CMakeLists.txt b/intern/cycles/kernel/shaders/CMakeLists.txt
deleted file mode 100644
index 02be7813369..00000000000
--- a/intern/cycles/kernel/shaders/CMakeLists.txt
+++ /dev/null
@@ -1,154 +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.
-
-# OSL node shaders
-
-set(SRC_OSL
- node_add_closure.osl
- node_ambient_occlusion.osl
- node_anisotropic_bsdf.osl
- node_attribute.osl
- node_background.osl
- node_bevel.osl
- node_brick_texture.osl
- node_brightness.osl
- node_bump.osl
- node_camera.osl
- node_checker_texture.osl
- node_clamp.osl
- node_combine_rgb.osl
- node_combine_hsv.osl
- node_combine_xyz.osl
- node_convert_from_color.osl
- node_convert_from_float.osl
- node_convert_from_int.osl
- node_convert_from_normal.osl
- node_convert_from_point.osl
- node_convert_from_vector.osl
- node_diffuse_bsdf.osl
- node_displacement.osl
- node_vector_displacement.osl
- node_emission.osl
- node_environment_texture.osl
- node_fresnel.osl
- node_gamma.osl
- node_geometry.osl
- node_glass_bsdf.osl
- node_glossy_bsdf.osl
- node_gradient_texture.osl
- node_hair_info.osl
- node_scatter_volume.osl
- node_absorption_volume.osl
- node_principled_volume.osl
- node_holdout.osl
- node_hsv.osl
- node_ies_light.osl
- node_image_texture.osl
- node_invert.osl
- node_layer_weight.osl
- node_light_falloff.osl
- node_light_path.osl
- node_magic_texture.osl
- node_map_range.osl
- node_mapping.osl
- node_math.osl
- node_mix.osl
- node_mix_closure.osl
- node_musgrave_texture.osl
- node_noise_texture.osl
- node_normal.osl
- node_normal_map.osl
- node_object_info.osl
- node_output_displacement.osl
- node_output_surface.osl
- node_output_volume.osl
- node_particle_info.osl
- node_refraction_bsdf.osl
- node_rgb_curves.osl
- node_rgb_ramp.osl
- node_separate_rgb.osl
- node_separate_hsv.osl
- node_separate_xyz.osl
- node_set_normal.osl
- node_sky_texture.osl
- node_subsurface_scattering.osl
- node_tangent.osl
- node_texture_coordinate.osl
- node_toon_bsdf.osl
- node_translucent_bsdf.osl
- node_transparent_bsdf.osl
- node_value.osl
- node_vector_curves.osl
- node_vector_math.osl
- node_vector_rotate.osl
- node_vector_transform.osl
- node_velvet_bsdf.osl
- node_vertex_color.osl
- node_voronoi_texture.osl
- node_voxel_texture.osl
- node_wavelength.osl
- node_blackbody.osl
- node_wave_texture.osl
- node_white_noise_texture.osl
- node_wireframe.osl
- node_hair_bsdf.osl
- node_principled_hair_bsdf.osl
- node_uv_map.osl
- node_principled_bsdf.osl
- node_rgb_to_bw.osl
-)
-
-# The headers that OSL ships differs per release so we can not
-# hardcode this.
-file(GLOB SRC_OSL_HEADER_DIST ${OSL_SHADER_DIR}/*.h)
-
-set(SRC_OSL_HEADERS
- node_color.h
- node_fresnel.h
- node_hash.h
- node_math.h
- node_noise.h
- node_ramp_util.h
- stdcycles.h
- ${SRC_OSL_HEADER_DIST}
-)
-
-set(SRC_OSO
-
-)
-
-# TODO, add a module to compile OSL
-foreach(_file ${SRC_OSL})
- set(_OSL_FILE ${CMAKE_CURRENT_SOURCE_DIR}/${_file})
- set_source_files_properties(${_file} PROPERTIES HEADER_FILE_ONLY TRUE)
- string(REPLACE ".osl" ".oso" _OSO_FILE ${_OSL_FILE})
- string(REPLACE ${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} _OSO_FILE ${_OSO_FILE})
- add_custom_command(
- OUTPUT ${_OSO_FILE}
- COMMAND ${OSL_COMPILER} -q -O2 -I"${CMAKE_CURRENT_SOURCE_DIR}" -I"${OSL_SHADER_DIR}" -o ${_OSO_FILE} ${_OSL_FILE}
- DEPENDS ${_OSL_FILE} ${SRC_OSL_HEADERS} ${OSL_COMPILER})
- list(APPEND SRC_OSO
- ${_OSO_FILE}
- )
-
- unset(_OSL_FILE)
- unset(_OSO_FILE)
-endforeach()
-
-add_custom_target(cycles_osl_shaders ALL DEPENDS ${SRC_OSO} ${SRC_OSL_HEADERS} ${OSL_COMPILER} SOURCES ${SRC_OSL})
-cycles_set_solution_folder(cycles_osl_shaders)
-
-# CMAKE_CURRENT_SOURCE_DIR is already included in OSO paths
-delayed_install("" "${SRC_OSO}" ${CYCLES_INSTALL_PATH}/shader)
-delayed_install("${CMAKE_CURRENT_SOURCE_DIR}" "${SRC_OSL_HEADERS}" ${CYCLES_INSTALL_PATH}/shader)
diff --git a/intern/cycles/kernel/shaders/node_image_texture.osl b/intern/cycles/kernel/shaders/node_image_texture.osl
deleted file mode 100644
index 9e2ef84c872..00000000000
--- a/intern/cycles/kernel/shaders/node_image_texture.osl
+++ /dev/null
@@ -1,270 +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 "node_color.h"
-#include "stdcycles.h"
-
-point texco_remap_square(point co)
-{
- return (co - point(0.5, 0.5, 0.5)) * 2.0;
-}
-
-point map_to_tube(vector dir)
-{
- float u, v;
- v = (dir[2] + 1.0) * 0.5;
- float len = sqrt(dir[0] * dir[0] + dir[1] * dir[1]);
- if (len > 0.0) {
- u = (1.0 - (atan2(dir[0] / len, dir[1] / len) / M_PI)) * 0.5;
- }
- else {
- v = u = 0.0; /* To avoid un-initialized variables. */
- }
- return point(u, v, 0.0);
-}
-
-point map_to_sphere(vector dir)
-{
- float len = length(dir);
- float v, u;
- if (len > 0.0) {
- if (dir[0] == 0.0 && dir[1] == 0.0) {
- u = 0.0; /* Otherwise domain error. */
- }
- else {
- u = (1.0 - atan2(dir[0], dir[1]) / M_PI) / 2.0;
- }
- v = 1.0 - acos(dir[2] / len) / M_PI;
- }
- else {
- v = u = 0.0; /* To avoid un-initialized variables. */
- }
- return point(u, v, 0.0);
-}
-
-color image_texture_lookup(string filename,
- float u,
- float v,
- output float Alpha,
- int compress_as_srgb,
- int ignore_alpha,
- int unassociate_alpha,
- int is_float,
- int is_tiled,
- string interpolation,
- string extension)
-{
- /* Flip the y coordinate, but preserve UDIM tiles. */
- float flip_v;
- if (is_tiled) {
- float v_i = (int)v;
- flip_v = v_i + (1.0 - (v - v_i));
- }
- else {
- flip_v = 1.0 - v;
- }
- color rgb = (color)texture(
- filename, u, flip_v, "wrap", extension, "interp", interpolation, "alpha", Alpha);
-
- if (ignore_alpha) {
- Alpha = 1.0;
- }
- else if (unassociate_alpha) {
- rgb = color_unpremultiply(rgb, Alpha);
-
- if (!is_float)
- rgb = min(rgb, 1.0);
- }
-
- if (compress_as_srgb) {
- rgb = color_srgb_to_scene_linear(rgb);
- }
-
- return rgb;
-}
-
-shader node_image_texture(int use_mapping = 0,
- matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
- point Vector = P,
- string filename = "",
- string projection = "flat",
- string interpolation = "smartcubic",
- string extension = "periodic",
- float projection_blend = 0.0,
- int compress_as_srgb = 0,
- int ignore_alpha = 0,
- int unassociate_alpha = 0,
- int is_tiled = 0,
- int is_float = 1,
- output color Color = 0.0,
- output float Alpha = 1.0)
-{
- point p = Vector;
-
- if (use_mapping)
- p = transform(mapping, p);
-
- if (projection == "flat") {
- Color = image_texture_lookup(filename,
- p[0],
- p[1],
- Alpha,
- compress_as_srgb,
- ignore_alpha,
- unassociate_alpha,
- is_float,
- is_tiled,
- interpolation,
- extension);
- }
- else if (projection == "box") {
- /* object space normal */
- vector Nob = transform("world", "object", N);
-
- /* project from direction vector to barycentric coordinates in triangles */
- Nob = vector(fabs(Nob[0]), fabs(Nob[1]), fabs(Nob[2]));
- Nob /= (Nob[0] + Nob[1] + Nob[2]);
-
- /* 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 */
-
- vector weight = vector(0.0, 0.0, 0.0);
- float blend = projection_blend;
- float limit = 0.5 * (1.0 + blend);
-
- /* first test for corners with single texture */
- if (Nob[0] > limit * (Nob[0] + Nob[1]) && Nob[0] > limit * (Nob[0] + Nob[2])) {
- weight[0] = 1.0;
- }
- else if (Nob[1] > limit * (Nob[0] + Nob[1]) && Nob[1] > limit * (Nob[1] + Nob[2])) {
- weight[1] = 1.0;
- }
- else if (Nob[2] > limit * (Nob[0] + Nob[2]) && Nob[2] > limit * (Nob[1] + Nob[2])) {
- weight[2] = 1.0;
- }
- else if (blend > 0.0) {
- /* in case of blending, test for mixes between two textures */
- if (Nob[2] < (1.0 - limit) * (Nob[1] + Nob[0])) {
- weight[0] = Nob[0] / (Nob[0] + Nob[1]);
- weight[0] = clamp((weight[0] - 0.5 * (1.0 - blend)) / blend, 0.0, 1.0);
- weight[1] = 1.0 - weight[0];
- }
- else if (Nob[0] < (1.0 - limit) * (Nob[1] + Nob[2])) {
- weight[1] = Nob[1] / (Nob[1] + Nob[2]);
- weight[1] = clamp((weight[1] - 0.5 * (1.0 - blend)) / blend, 0.0, 1.0);
- weight[2] = 1.0 - weight[1];
- }
- else if (Nob[1] < (1.0 - limit) * (Nob[0] + Nob[2])) {
- weight[0] = Nob[0] / (Nob[0] + Nob[2]);
- weight[0] = clamp((weight[0] - 0.5 * (1.0 - blend)) / blend, 0.0, 1.0);
- weight[2] = 1.0 - weight[0];
- }
- else {
- /* last case, we have a mix between three */
- weight[0] = ((2.0 - limit) * Nob[0] + (limit - 1.0)) / (2.0 * limit - 1.0);
- weight[1] = ((2.0 - limit) * Nob[1] + (limit - 1.0)) / (2.0 * limit - 1.0);
- weight[2] = ((2.0 - limit) * Nob[2] + (limit - 1.0)) / (2.0 * limit - 1.0);
- }
- }
- else {
- /* Desperate mode, no valid choice anyway, fallback to one side.*/
- weight[0] = 1.0;
- }
-
- Color = color(0.0, 0.0, 0.0);
- Alpha = 0.0;
-
- float tmp_alpha;
-
- if (weight[0] > 0.0) {
- Color += weight[0] * image_texture_lookup(filename,
- p[1],
- p[2],
- tmp_alpha,
- compress_as_srgb,
- ignore_alpha,
- unassociate_alpha,
- is_float,
- 0,
- interpolation,
- extension);
- Alpha += weight[0] * tmp_alpha;
- }
- if (weight[1] > 0.0) {
- Color += weight[1] * image_texture_lookup(filename,
- p[0],
- p[2],
- tmp_alpha,
- compress_as_srgb,
- ignore_alpha,
- unassociate_alpha,
- is_float,
- 0,
- interpolation,
- extension);
- Alpha += weight[1] * tmp_alpha;
- }
- if (weight[2] > 0.0) {
- Color += weight[2] * image_texture_lookup(filename,
- p[1],
- p[0],
- tmp_alpha,
- compress_as_srgb,
- ignore_alpha,
- unassociate_alpha,
- is_float,
- 0,
- interpolation,
- extension);
- Alpha += weight[2] * tmp_alpha;
- }
- }
- else if (projection == "sphere") {
- point projected = map_to_sphere(texco_remap_square(p));
- Color = image_texture_lookup(filename,
- projected[0],
- projected[1],
- Alpha,
- compress_as_srgb,
- ignore_alpha,
- unassociate_alpha,
- is_float,
- 0,
- interpolation,
- extension);
- }
- else if (projection == "tube") {
- point projected = map_to_tube(texco_remap_square(p));
- Color = image_texture_lookup(filename,
- projected[0],
- projected[1],
- Alpha,
- compress_as_srgb,
- ignore_alpha,
- unassociate_alpha,
- is_float,
- 0,
- interpolation,
- extension);
- }
-}
diff --git a/intern/cycles/kernel/shaders/node_magic_texture.osl b/intern/cycles/kernel/shaders/node_magic_texture.osl
deleted file mode 100644
index 476c6895f05..00000000000
--- a/intern/cycles/kernel/shaders/node_magic_texture.osl
+++ /dev/null
@@ -1,108 +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 "stdcycles.h"
-
-/* Magic */
-
-color magic(point p, int n, float distortion)
-{
- float dist = distortion;
-
- float x = sin((p[0] + p[1] + p[2]) * 5.0);
- float y = cos((-p[0] + p[1] - p[2]) * 5.0);
- float z = -cos((-p[0] - p[1] + p[2]) * 5.0);
-
- if (n > 0) {
- x *= dist;
- y *= dist;
- z *= dist;
- y = -cos(x - y + z);
- y *= dist;
-
- if (n > 1) {
- x = cos(x - y - z);
- x *= dist;
-
- if (n > 2) {
- z = sin(-x - y - z);
- z *= dist;
-
- if (n > 3) {
- x = -cos(-x + y - z);
- x *= dist;
-
- if (n > 4) {
- y = -sin(-x + y + z);
- y *= dist;
-
- if (n > 5) {
- y = -cos(-x + y + z);
- y *= dist;
-
- if (n > 6) {
- x = cos(x + y + z);
- x *= dist;
-
- if (n > 7) {
- z = sin(x + y - z);
- z *= dist;
-
- if (n > 8) {
- x = -cos(-x - y + z);
- x *= dist;
-
- if (n > 9) {
- y = -sin(x - y + z);
- y *= dist;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
-
- if (dist != 0.0) {
- dist *= 2.0;
- x /= dist;
- y /= dist;
- z /= dist;
- }
-
- return color(0.5 - x, 0.5 - y, 0.5 - z);
-}
-
-shader node_magic_texture(int use_mapping = 0,
- matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
- int depth = 2,
- float Distortion = 5.0,
- float Scale = 5.0,
- point Vector = P,
- output float Fac = 0.0,
- output color Color = 0.0)
-{
- point p = Vector;
-
- if (use_mapping)
- p = transform(mapping, p);
-
- Color = magic(p * Scale, depth, Distortion);
- Fac = (Color[0] + Color[1] + Color[2]) * (1.0 / 3.0);
-}
diff --git a/intern/cycles/kernel/shaders/node_musgrave_texture.osl b/intern/cycles/kernel/shaders/node_musgrave_texture.osl
deleted file mode 100644
index 0e71ce74c29..00000000000
--- a/intern/cycles/kernel/shaders/node_musgrave_texture.osl
+++ /dev/null
@@ -1,803 +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 "node_noise.h"
-#include "stdcycles.h"
-#include "vector2.h"
-#include "vector4.h"
-
-#define vector3 point
-
-/* 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"
- */
-
-float noise_musgrave_fBm_1d(float co, float H, float lacunarity, float octaves)
-{
- float p = co;
- float value = 0.0;
- float pwr = 1.0;
- float pwHL = pow(lacunarity, -H);
-
- for (int i = 0; i < (int)octaves; i++) {
- value += safe_snoise(p) * pwr;
- pwr *= pwHL;
- p *= lacunarity;
- }
-
- float rmd = octaves - floor(octaves);
- if (rmd != 0.0) {
- value += rmd * safe_snoise(p) * pwr;
- }
-
- return value;
-}
-
-/* 1D Musgrave Multifractal
- *
- * H: highest fractal dimension
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- */
-
-float noise_musgrave_multi_fractal_1d(float co, float H, float lacunarity, float octaves)
-{
- float p = co;
- float value = 1.0;
- float pwr = 1.0;
- float pwHL = pow(lacunarity, -H);
-
- for (int i = 0; i < (int)octaves; i++) {
- value *= (pwr * safe_snoise(p) + 1.0);
- pwr *= pwHL;
- p *= lacunarity;
- }
-
- float rmd = octaves - floor(octaves);
- if (rmd != 0.0) {
- value *= (rmd * pwr * safe_snoise(p) + 1.0); /* 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'
- */
-
-float noise_musgrave_hetero_terrain_1d(
- float co, float H, float lacunarity, float octaves, float offset)
-{
- float p = co;
- float pwHL = pow(lacunarity, -H);
- float pwr = pwHL;
-
- /* first unscaled octave of function; later octaves are scaled */
- float value = offset + safe_snoise(p);
- p *= lacunarity;
-
- for (int i = 1; i < (int)octaves; i++) {
- float increment = (safe_snoise(p) + offset) * pwr * value;
- value += increment;
- pwr *= pwHL;
- p *= lacunarity;
- }
-
- float rmd = octaves - floor(octaves);
- if (rmd != 0.0) {
- float increment = (safe_snoise(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'
- */
-
-float noise_musgrave_hybrid_multi_fractal_1d(
- float co, float H, float lacunarity, float octaves, float offset, float gain)
-{
- float p = co;
- float pwHL = pow(lacunarity, -H);
- float pwr = pwHL;
-
- float value = safe_snoise(p) + offset;
- float weight = gain * value;
- p *= lacunarity;
-
- for (int i = 1; (weight > 0.001) && (i < (int)octaves); i++) {
- if (weight > 1.0) {
- weight = 1.0;
- }
-
- float signal = (safe_snoise(p) + offset) * pwr;
- pwr *= pwHL;
- value += weight * signal;
- weight *= gain * signal;
- p *= lacunarity;
- }
-
- float rmd = octaves - floor(octaves);
- if (rmd != 0.0) {
- value += rmd * ((safe_snoise(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'
- */
-
-float noise_musgrave_ridged_multi_fractal_1d(
- float co, float H, float lacunarity, float octaves, float offset, float gain)
-{
- float p = co;
- float pwHL = pow(lacunarity, -H);
- float pwr = pwHL;
-
- float signal = offset - fabs(safe_snoise(p));
- signal *= signal;
- float value = signal;
- float weight = 1.0;
-
- for (int i = 1; i < (int)octaves; i++) {
- p *= lacunarity;
- weight = clamp(signal * gain, 0.0, 1.0);
- signal = offset - fabs(safe_snoise(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"
- */
-
-float noise_musgrave_fBm_2d(vector2 co, float H, float lacunarity, float octaves)
-{
- vector2 p = co;
- float value = 0.0;
- float pwr = 1.0;
- float pwHL = pow(lacunarity, -H);
-
- for (int i = 0; i < (int)octaves; i++) {
- value += safe_snoise(p) * pwr;
- pwr *= pwHL;
- p *= lacunarity;
- }
-
- float rmd = octaves - floor(octaves);
- if (rmd != 0.0) {
- value += rmd * safe_snoise(p) * pwr;
- }
-
- return value;
-}
-
-/* 2D Musgrave Multifractal
- *
- * H: highest fractal dimension
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- */
-
-float noise_musgrave_multi_fractal_2d(vector2 co, float H, float lacunarity, float octaves)
-{
- vector2 p = co;
- float value = 1.0;
- float pwr = 1.0;
- float pwHL = pow(lacunarity, -H);
-
- for (int i = 0; i < (int)octaves; i++) {
- value *= (pwr * safe_snoise(p) + 1.0);
- pwr *= pwHL;
- p *= lacunarity;
- }
-
- float rmd = octaves - floor(octaves);
- if (rmd != 0.0) {
- value *= (rmd * pwr * safe_snoise(p) + 1.0); /* 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'
- */
-
-float noise_musgrave_hetero_terrain_2d(
- vector2 co, float H, float lacunarity, float octaves, float offset)
-{
- vector2 p = co;
- float pwHL = pow(lacunarity, -H);
- float pwr = pwHL;
-
- /* first unscaled octave of function; later octaves are scaled */
- float value = offset + safe_snoise(p);
- p *= lacunarity;
-
- for (int i = 1; i < (int)octaves; i++) {
- float increment = (safe_snoise(p) + offset) * pwr * value;
- value += increment;
- pwr *= pwHL;
- p *= lacunarity;
- }
-
- float rmd = octaves - floor(octaves);
- if (rmd != 0.0) {
- float increment = (safe_snoise(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'
- */
-
-float noise_musgrave_hybrid_multi_fractal_2d(
- vector2 co, float H, float lacunarity, float octaves, float offset, float gain)
-{
- vector2 p = co;
- float pwHL = pow(lacunarity, -H);
- float pwr = pwHL;
-
- float value = safe_snoise(p) + offset;
- float weight = gain * value;
- p *= lacunarity;
-
- for (int i = 1; (weight > 0.001) && (i < (int)octaves); i++) {
- if (weight > 1.0) {
- weight = 1.0;
- }
-
- float signal = (safe_snoise(p) + offset) * pwr;
- pwr *= pwHL;
- value += weight * signal;
- weight *= gain * signal;
- p *= lacunarity;
- }
-
- float rmd = octaves - floor(octaves);
- if (rmd != 0.0) {
- value += rmd * ((safe_snoise(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'
- */
-
-float noise_musgrave_ridged_multi_fractal_2d(
- vector2 co, float H, float lacunarity, float octaves, float offset, float gain)
-{
- vector2 p = co;
- float pwHL = pow(lacunarity, -H);
- float pwr = pwHL;
-
- float signal = offset - fabs(safe_snoise(p));
- signal *= signal;
- float value = signal;
- float weight = 1.0;
-
- for (int i = 1; i < (int)octaves; i++) {
- p *= lacunarity;
- weight = clamp(signal * gain, 0.0, 1.0);
- signal = offset - fabs(safe_snoise(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"
- */
-
-float noise_musgrave_fBm_3d(vector3 co, float H, float lacunarity, float octaves)
-{
- vector3 p = co;
- float value = 0.0;
- float pwr = 1.0;
- float pwHL = pow(lacunarity, -H);
-
- for (int i = 0; i < (int)octaves; i++) {
- value += safe_snoise(p) * pwr;
- pwr *= pwHL;
- p *= lacunarity;
- }
-
- float rmd = octaves - floor(octaves);
- if (rmd != 0.0) {
- value += rmd * safe_snoise(p) * pwr;
- }
-
- return value;
-}
-
-/* 3D Musgrave Multifractal
- *
- * H: highest fractal dimension
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- */
-
-float noise_musgrave_multi_fractal_3d(vector3 co, float H, float lacunarity, float octaves)
-{
- vector3 p = co;
- float value = 1.0;
- float pwr = 1.0;
- float pwHL = pow(lacunarity, -H);
-
- for (int i = 0; i < (int)octaves; i++) {
- value *= (pwr * safe_snoise(p) + 1.0);
- pwr *= pwHL;
- p *= lacunarity;
- }
-
- float rmd = octaves - floor(octaves);
- if (rmd != 0.0) {
- value *= (rmd * pwr * safe_snoise(p) + 1.0); /* 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'
- */
-
-float noise_musgrave_hetero_terrain_3d(
- vector3 co, float H, float lacunarity, float octaves, float offset)
-{
- vector3 p = co;
- float pwHL = pow(lacunarity, -H);
- float pwr = pwHL;
-
- /* first unscaled octave of function; later octaves are scaled */
- float value = offset + safe_snoise(p);
- p *= lacunarity;
-
- for (int i = 1; i < (int)octaves; i++) {
- float increment = (safe_snoise(p) + offset) * pwr * value;
- value += increment;
- pwr *= pwHL;
- p *= lacunarity;
- }
-
- float rmd = octaves - floor(octaves);
- if (rmd != 0.0) {
- float increment = (safe_snoise(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'
- */
-
-float noise_musgrave_hybrid_multi_fractal_3d(
- vector3 co, float H, float lacunarity, float octaves, float offset, float gain)
-{
- vector3 p = co;
- float pwHL = pow(lacunarity, -H);
- float pwr = pwHL;
-
- float value = safe_snoise(p) + offset;
- float weight = gain * value;
- p *= lacunarity;
-
- for (int i = 1; (weight > 0.001) && (i < (int)octaves); i++) {
- if (weight > 1.0) {
- weight = 1.0;
- }
-
- float signal = (safe_snoise(p) + offset) * pwr;
- pwr *= pwHL;
- value += weight * signal;
- weight *= gain * signal;
- p *= lacunarity;
- }
-
- float rmd = octaves - floor(octaves);
- if (rmd != 0.0) {
- value += rmd * ((safe_snoise(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'
- */
-
-float noise_musgrave_ridged_multi_fractal_3d(
- vector3 co, float H, float lacunarity, float octaves, float offset, float gain)
-{
- vector3 p = co;
- float pwHL = pow(lacunarity, -H);
- float pwr = pwHL;
-
- float signal = offset - fabs(safe_snoise(p));
- signal *= signal;
- float value = signal;
- float weight = 1.0;
-
- for (int i = 1; i < (int)octaves; i++) {
- p *= lacunarity;
- weight = clamp(signal * gain, 0.0, 1.0);
- signal = offset - fabs(safe_snoise(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"
- */
-
-float noise_musgrave_fBm_4d(vector4 co, float H, float lacunarity, float octaves)
-{
- vector4 p = co;
- float value = 0.0;
- float pwr = 1.0;
- float pwHL = pow(lacunarity, -H);
-
- for (int i = 0; i < (int)octaves; i++) {
- value += safe_snoise(p) * pwr;
- pwr *= pwHL;
- p *= lacunarity;
- }
-
- float rmd = octaves - floor(octaves);
- if (rmd != 0.0) {
- value += rmd * safe_snoise(p) * pwr;
- }
-
- return value;
-}
-
-/* 4D Musgrave Multifractal
- *
- * H: highest fractal dimension
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- */
-
-float noise_musgrave_multi_fractal_4d(vector4 co, float H, float lacunarity, float octaves)
-{
- vector4 p = co;
- float value = 1.0;
- float pwr = 1.0;
- float pwHL = pow(lacunarity, -H);
-
- for (int i = 0; i < (int)octaves; i++) {
- value *= (pwr * safe_snoise(p) + 1.0);
- pwr *= pwHL;
- p *= lacunarity;
- }
-
- float rmd = octaves - floor(octaves);
- if (rmd != 0.0) {
- value *= (rmd * pwr * safe_snoise(p) + 1.0); /* 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'
- */
-
-float noise_musgrave_hetero_terrain_4d(
- vector4 co, float H, float lacunarity, float octaves, float offset)
-{
- vector4 p = co;
- float pwHL = pow(lacunarity, -H);
- float pwr = pwHL;
-
- /* first unscaled octave of function; later octaves are scaled */
- float value = offset + safe_snoise(p);
- p *= lacunarity;
-
- for (int i = 1; i < (int)octaves; i++) {
- float increment = (safe_snoise(p) + offset) * pwr * value;
- value += increment;
- pwr *= pwHL;
- p *= lacunarity;
- }
-
- float rmd = octaves - floor(octaves);
- if (rmd != 0.0) {
- float increment = (safe_snoise(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'
- */
-
-float noise_musgrave_hybrid_multi_fractal_4d(
- vector4 co, float H, float lacunarity, float octaves, float offset, float gain)
-{
- vector4 p = co;
- float pwHL = pow(lacunarity, -H);
- float pwr = pwHL;
-
- float value = safe_snoise(p) + offset;
- float weight = gain * value;
- p *= lacunarity;
-
- for (int i = 1; (weight > 0.001) && (i < (int)octaves); i++) {
- if (weight > 1.0) {
- weight = 1.0;
- }
-
- float signal = (safe_snoise(p) + offset) * pwr;
- pwr *= pwHL;
- value += weight * signal;
- weight *= gain * signal;
- p *= lacunarity;
- }
-
- float rmd = octaves - floor(octaves);
- if (rmd != 0.0) {
- value += rmd * ((safe_snoise(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'
- */
-
-float noise_musgrave_ridged_multi_fractal_4d(
- vector4 co, float H, float lacunarity, float octaves, float offset, float gain)
-{
- vector4 p = co;
- float pwHL = pow(lacunarity, -H);
- float pwr = pwHL;
-
- float signal = offset - fabs(safe_snoise(p));
- signal *= signal;
- float value = signal;
- float weight = 1.0;
-
- for (int i = 1; i < (int)octaves; i++) {
- p *= lacunarity;
- weight = clamp(signal * gain, 0.0, 1.0);
- signal = offset - fabs(safe_snoise(p));
- signal *= signal;
- signal *= weight;
- value += signal * pwr;
- pwr *= pwHL;
- }
-
- return value;
-}
-
-shader node_musgrave_texture(
- int use_mapping = 0,
- matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
- string musgrave_type = "fBM",
- string dimensions = "3D",
- point Vector = P,
- float W = 0.0,
- float Dimension = 2.0,
- float Scale = 5.0,
- float Detail = 2.0,
- float Lacunarity = 2.0,
- float Offset = 0.0,
- float Gain = 1.0,
- output float Fac = 0.0)
-{
- float dimension = max(Dimension, 1e-5);
- float octaves = clamp(Detail, 0.0, 16.0);
- float lacunarity = max(Lacunarity, 1e-5);
-
- vector3 s = Vector;
-
- if (use_mapping)
- s = transform(mapping, s);
-
- if (dimensions == "1D") {
- float p = W * Scale;
- if (musgrave_type == "multifractal") {
- Fac = noise_musgrave_multi_fractal_1d(p, dimension, lacunarity, octaves);
- }
- else if (musgrave_type == "fBM") {
- Fac = noise_musgrave_fBm_1d(p, dimension, lacunarity, octaves);
- }
- else if (musgrave_type == "hybrid_multifractal") {
- Fac = noise_musgrave_hybrid_multi_fractal_1d(
- p, dimension, lacunarity, octaves, Offset, Gain);
- }
- else if (musgrave_type == "ridged_multifractal") {
- Fac = noise_musgrave_ridged_multi_fractal_1d(
- p, dimension, lacunarity, octaves, Offset, Gain);
- }
- else if (musgrave_type == "hetero_terrain") {
- Fac = noise_musgrave_hetero_terrain_1d(p, dimension, lacunarity, octaves, Offset);
- }
- else {
- Fac = 0.0;
- }
- }
- else if (dimensions == "2D") {
- vector2 p = vector2(s[0], s[1]) * Scale;
- if (musgrave_type == "multifractal") {
- Fac = noise_musgrave_multi_fractal_2d(p, dimension, lacunarity, octaves);
- }
- else if (musgrave_type == "fBM") {
- Fac = noise_musgrave_fBm_2d(p, dimension, lacunarity, octaves);
- }
- else if (musgrave_type == "hybrid_multifractal") {
- Fac = noise_musgrave_hybrid_multi_fractal_2d(
- p, dimension, lacunarity, octaves, Offset, Gain);
- }
- else if (musgrave_type == "ridged_multifractal") {
- Fac = noise_musgrave_ridged_multi_fractal_2d(
- p, dimension, lacunarity, octaves, Offset, Gain);
- }
- else if (musgrave_type == "hetero_terrain") {
- Fac = noise_musgrave_hetero_terrain_2d(p, dimension, lacunarity, octaves, Offset);
- }
- else {
- Fac = 0.0;
- }
- }
- else if (dimensions == "3D") {
- vector3 p = s * Scale;
- if (musgrave_type == "multifractal") {
- Fac = noise_musgrave_multi_fractal_3d(p, dimension, lacunarity, octaves);
- }
- else if (musgrave_type == "fBM") {
- Fac = noise_musgrave_fBm_3d(p, dimension, lacunarity, octaves);
- }
- else if (musgrave_type == "hybrid_multifractal") {
- Fac = noise_musgrave_hybrid_multi_fractal_3d(
- p, dimension, lacunarity, octaves, Offset, Gain);
- }
- else if (musgrave_type == "ridged_multifractal") {
- Fac = noise_musgrave_ridged_multi_fractal_3d(
- p, dimension, lacunarity, octaves, Offset, Gain);
- }
- else if (musgrave_type == "hetero_terrain") {
- Fac = noise_musgrave_hetero_terrain_3d(p, dimension, lacunarity, octaves, Offset);
- }
- else {
- Fac = 0.0;
- }
- }
- else if (dimensions == "4D") {
- vector4 p = vector4(s[0], s[1], s[2], W) * Scale;
- if (musgrave_type == "multifractal") {
- Fac = noise_musgrave_multi_fractal_4d(p, dimension, lacunarity, octaves);
- }
- else if (musgrave_type == "fBM") {
- Fac = noise_musgrave_fBm_4d(p, dimension, lacunarity, octaves);
- }
- else if (musgrave_type == "hybrid_multifractal") {
- Fac = noise_musgrave_hybrid_multi_fractal_4d(
- p, dimension, lacunarity, octaves, Offset, Gain);
- }
- else if (musgrave_type == "ridged_multifractal") {
- Fac = noise_musgrave_ridged_multi_fractal_4d(
- p, dimension, lacunarity, octaves, Offset, Gain);
- }
- else if (musgrave_type == "hetero_terrain") {
- Fac = noise_musgrave_hetero_terrain_4d(p, dimension, lacunarity, octaves, Offset);
- }
- else {
- Fac = 0.0;
- }
- }
- else {
- Fac = 0.0;
- }
-}
diff --git a/intern/cycles/kernel/shaders/node_noise.h b/intern/cycles/kernel/shaders/node_noise.h
deleted file mode 100644
index ab4cd7792cc..00000000000
--- a/intern/cycles/kernel/shaders/node_noise.h
+++ /dev/null
@@ -1,202 +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 "vector2.h"
-#include "vector4.h"
-
-#define vector3 point
-
-float safe_noise(float p)
-{
- float f = noise("noise", p);
- if (isinf(f))
- return 0.5;
- return f;
-}
-
-float safe_noise(vector2 p)
-{
- float f = noise("noise", p.x, p.y);
- if (isinf(f))
- return 0.5;
- return f;
-}
-
-float safe_noise(vector3 p)
-{
- float f = noise("noise", p);
- if (isinf(f))
- return 0.5;
- return f;
-}
-
-float safe_noise(vector4 p)
-{
- float f = noise("noise", vector3(p.x, p.y, p.z), p.w);
- if (isinf(f))
- return 0.5;
- return f;
-}
-
-float safe_snoise(float p)
-{
- float f = noise("snoise", p);
- if (isinf(f))
- return 0.0;
- return f;
-}
-
-float safe_snoise(vector2 p)
-{
- float f = noise("snoise", p.x, p.y);
- if (isinf(f))
- return 0.0;
- return f;
-}
-
-float safe_snoise(vector3 p)
-{
- float f = noise("snoise", p);
- if (isinf(f))
- return 0.0;
- return f;
-}
-
-float safe_snoise(vector4 p)
-{
- float f = noise("snoise", vector3(p.x, p.y, p.z), p.w);
- if (isinf(f))
- return 0.0;
- return f;
-}
-
-/* The fractal_noise functions are all exactly the same except for the input type. */
-float fractal_noise(float p, float details, float roughness)
-{
- float fscale = 1.0;
- float amp = 1.0;
- float maxamp = 0.0;
- float sum = 0.0;
- float octaves = clamp(details, 0.0, 16.0);
- int n = (int)octaves;
- for (int i = 0; i <= n; i++) {
- float t = safe_noise(fscale * p);
- sum += t * amp;
- maxamp += amp;
- amp *= clamp(roughness, 0.0, 1.0);
- fscale *= 2.0;
- }
- float rmd = octaves - floor(octaves);
- if (rmd != 0.0) {
- float t = safe_noise(fscale * p);
- float sum2 = sum + t * amp;
- sum /= maxamp;
- sum2 /= maxamp + amp;
- return (1.0 - rmd) * sum + rmd * sum2;
- }
- else {
- return sum / maxamp;
- }
-}
-
-/* The fractal_noise functions are all exactly the same except for the input type. */
-float fractal_noise(vector2 p, float details, float roughness)
-{
- float fscale = 1.0;
- float amp = 1.0;
- float maxamp = 0.0;
- float sum = 0.0;
- float octaves = clamp(details, 0.0, 16.0);
- int n = (int)octaves;
- for (int i = 0; i <= n; i++) {
- float t = safe_noise(fscale * p);
- sum += t * amp;
- maxamp += amp;
- amp *= clamp(roughness, 0.0, 1.0);
- fscale *= 2.0;
- }
- float rmd = octaves - floor(octaves);
- if (rmd != 0.0) {
- float t = safe_noise(fscale * p);
- float sum2 = sum + t * amp;
- sum /= maxamp;
- sum2 /= maxamp + amp;
- return (1.0 - rmd) * sum + rmd * sum2;
- }
- else {
- return sum / maxamp;
- }
-}
-
-/* The fractal_noise functions are all exactly the same except for the input type. */
-float fractal_noise(vector3 p, float details, float roughness)
-{
- float fscale = 1.0;
- float amp = 1.0;
- float maxamp = 0.0;
- float sum = 0.0;
- float octaves = clamp(details, 0.0, 16.0);
- int n = (int)octaves;
- for (int i = 0; i <= n; i++) {
- float t = safe_noise(fscale * p);
- sum += t * amp;
- maxamp += amp;
- amp *= clamp(roughness, 0.0, 1.0);
- fscale *= 2.0;
- }
- float rmd = octaves - floor(octaves);
- if (rmd != 0.0) {
- float t = safe_noise(fscale * p);
- float sum2 = sum + t * amp;
- sum /= maxamp;
- sum2 /= maxamp + amp;
- return (1.0 - rmd) * sum + rmd * sum2;
- }
- else {
- return sum / maxamp;
- }
-}
-
-/* The fractal_noise functions are all exactly the same except for the input type. */
-float fractal_noise(vector4 p, float details, float roughness)
-{
- float fscale = 1.0;
- float amp = 1.0;
- float maxamp = 0.0;
- float sum = 0.0;
- float octaves = clamp(details, 0.0, 16.0);
- int n = (int)octaves;
- for (int i = 0; i <= n; i++) {
- float t = safe_noise(fscale * p);
- sum += t * amp;
- maxamp += amp;
- amp *= clamp(roughness, 0.0, 1.0);
- fscale *= 2.0;
- }
- float rmd = octaves - floor(octaves);
- if (rmd != 0.0) {
- float t = safe_noise(fscale * p);
- float sum2 = sum + t * amp;
- sum /= maxamp;
- sum2 /= maxamp + amp;
- return (1.0 - rmd) * sum + rmd * sum2;
- }
- else {
- return sum / maxamp;
- }
-}
-
-#undef vector3
diff --git a/intern/cycles/kernel/shaders/node_normal_map.osl b/intern/cycles/kernel/shaders/node_normal_map.osl
deleted file mode 100644
index 6d4780f6dae..00000000000
--- a/intern/cycles/kernel/shaders/node_normal_map.osl
+++ /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.
- */
-
-#include "stdcycles.h"
-
-shader node_normal_map(normal NormalIn = N,
- float Strength = 1.0,
- color Color = color(0.5, 0.5, 1.0),
- string space = "tangent",
- string attr_name = "geom:tangent",
- string attr_sign_name = "geom:tangent_sign",
- output normal Normal = NormalIn)
-{
- color mcolor = 2.0 * color(Color[0] - 0.5, Color[1] - 0.5, Color[2] - 0.5);
- int is_backfacing = backfacing();
-
- if (space == "tangent") {
- vector tangent;
- vector ninterp;
- float tangent_sign;
- float is_smooth = 0.0;
-
- getattribute("geom:is_smooth", is_smooth);
- if (!is_smooth) {
- ninterp = normalize(transform("world", "object", Ng));
-
- /* the normal is already inverted, which is too soon for the math here */
- if (is_backfacing) {
- ninterp = -ninterp;
- }
- }
-
- // get _unnormalized_ interpolated normal and tangent
- if (getattribute(attr_name, tangent) && getattribute(attr_sign_name, tangent_sign) &&
- (!is_smooth || getattribute("geom:N", ninterp))) {
- // apply normal map
- vector B = tangent_sign * cross(ninterp, tangent);
- Normal = normalize(mcolor[0] * tangent + mcolor[1] * B + mcolor[2] * ninterp);
-
- // transform to world space
- Normal = normalize(transform("object", "world", Normal));
- }
- else {
- Normal = normal(0, 0, 0);
- }
- }
- else if (space == "object") {
- Normal = normalize(transform("object", "world", vector(mcolor)));
- }
- else if (space == "world") {
- Normal = normalize(vector(mcolor));
- }
- else if (space == "blender_object") {
- /* strange blender convention */
- mcolor[1] = -mcolor[1];
- mcolor[2] = -mcolor[2];
-
- Normal = normalize(transform("object", "world", vector(mcolor)));
- }
- else if (space == "blender_world") {
- /* strange blender convention */
- mcolor[1] = -mcolor[1];
- mcolor[2] = -mcolor[2];
-
- Normal = normalize(vector(mcolor));
- }
-
- /* invert normal for backfacing polygons */
- if (is_backfacing) {
- Normal = -Normal;
- }
-
- if (Strength != 1.0)
- Normal = normalize(NormalIn + (Normal - NormalIn) * max(Strength, 0.0));
-
- Normal = ensure_valid_reflection(Ng, I, Normal);
-}
diff --git a/intern/cycles/kernel/svm/ao.h b/intern/cycles/kernel/svm/ao.h
new file mode 100644
index 00000000000..dcb1a79717d
--- /dev/null
+++ b/intern/cycles/kernel/svm/ao.h
@@ -0,0 +1,145 @@
+/*
+ * 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 = sd->P;
+ ray.D = D.x * T + D.y * B + D.z * N;
+ ray.t = max_dist;
+ ray.time = sd->time;
+ ray.self.object = sd->object;
+ ray.self.prim = sd->prim;
+ ray.self.light_object = OBJECT_NONE;
+ ray.self.light_prim = PRIM_NONE;
+ 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..0beaf0babc6
--- /dev/null
+++ b/intern/cycles/kernel/svm/aov.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_TRANSPARENT_BACKGROUND) &&
+ (!(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..17301028528
--- /dev/null
+++ b/intern/cycles/kernel/svm/attribute.h
@@ -0,0 +1,352 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+ if (sd->object != OBJECT_NONE) {
+ 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;
+ if (sd->object != OBJECT_NONE) {
+ 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;
+ if (sd->object != OBJECT_NONE) {
+ 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..98b663299da
--- /dev/null
+++ b/intern/cycles/kernel/svm/bevel.h
@@ -0,0 +1,340 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+ ray.self.object = OBJECT_NONE;
+ ray.self.prim = PRIM_NONE;
+ ray.self.light_object = OBJECT_NONE;
+ ray.self.light_prim = PRIM_NONE;
+
+ /* 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_point_from_uv(kg,
+ sd,
+ isect.hits[hit].object,
+ isect.hits[hit].prim,
+ isect.hits[hit].u,
+ isect.hits[hit].v);
+ }
+# 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_point_from_uv(kg,
+ sd,
+ isect.hits[hit].object,
+ isect.hits[hit].prim,
+ isect.hits[hit].u,
+ isect.hits[hit].v,
+ 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..2ca22d58191
--- /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_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_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_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..8256a24c751
--- /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, 15.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, 15.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, 15.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, 15.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..225348b1ac2
--- /dev/null
+++ b/intern/cycles/kernel/svm/geometry.h
@@ -0,0 +1,278 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_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;
+ }
+ case NODE_INFO_CURVE_TANGENT_NORMAL: {
+ data3 = curve_tangent_normal(kg, sd);
+ stack_store_float3(stack, out_offset, data3);
+ break;
+ }
+ }
+}
+#endif
+
+#ifdef __POINTCLOUD__
+
+/* Point Info */
+
+ccl_device_noinline void svm_node_point_info(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint type,
+ uint out_offset)
+{
+ switch (type) {
+ case NODE_INFO_POINT_POSITION:
+ stack_store_float3(stack, out_offset, point_position(kg, sd));
+ break;
+ case NODE_INFO_POINT_RADIUS:
+ stack_store_float(stack, out_offset, point_radius(kg, sd));
+ break;
+ case NODE_INFO_POINT_RANDOM:
+ break; /* handled as attribute */
+ }
+}
+
+#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..cdd73a7829a
--- /dev/null
+++ b/intern/cycles/kernel/svm/magic.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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, float scale, int n, float distortion)
+{
+ /*
+ * Prevent NaNs due to input p
+ * Sin and Cosine are periodic about [0 2*PI) so the following
+ * will yield a more accurate result. As it stops the input values
+ * going out of range for floats which caused a NaN. The
+ * calculation of (px + py + pz)*5 can cause an Inf when one or more
+ * values are very large the cos or sin of this results in a NaN
+ * It also addresses the case where one dimension is large relative
+ * to another which caused banding due to the loss of precision in the
+ * smaller value. This is due to the value in the -2*PI to 2*PI range
+ * effectively being lost due to floating point precision.
+ */
+ float px = fmodf(p.x, M_2PI_F);
+ float py = fmodf(p.y, M_2PI_F);
+ float pz = fmodf(p.z, M_2PI_F);
+
+ float x = sinf((px + py + pz) * 5.0f * scale);
+ float y = cosf((-px + py - pz) * 5.0f * scale);
+ float z = -cosf((-px - py + pz) * 5.0f * scale);
+
+ 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..933ea84f939
--- /dev/null
+++ b/intern/cycles/kernel/svm/map_range.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
+
+/* 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_device_noinline int svm_node_vector_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 steps_stack_offset, clamp_stack_offset, range_type_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_uchar4(results_stack_offsets,
+ &steps_stack_offset,
+ &clamp_stack_offset,
+ &range_type_stack_offset,
+ &result_stack_offset);
+
+ float3 value = stack_load_float3(stack, value_stack_offset);
+ float3 from_min = stack_load_float3(stack, from_min_stack_offset);
+ float3 from_max = stack_load_float3(stack, from_max_stack_offset);
+ float3 to_min = stack_load_float3(stack, to_min_stack_offset);
+ float3 to_max = stack_load_float3(stack, to_max_stack_offset);
+ float3 steps = stack_load_float3(stack, steps_stack_offset);
+
+ int type = range_type_stack_offset;
+ int use_clamp = (type == NODE_MAP_RANGE_SMOOTHSTEP || type == NODE_MAP_RANGE_SMOOTHERSTEP) ?
+ 0 :
+ clamp_stack_offset;
+ float3 result;
+ float3 factor = value;
+ switch (range_type_stack_offset) {
+ default:
+ case NODE_MAP_RANGE_LINEAR:
+ factor = safe_divide_float3_float3((value - from_min), (from_max - from_min));
+ break;
+ case NODE_MAP_RANGE_STEPPED: {
+ factor = safe_divide_float3_float3((value - from_min), (from_max - from_min));
+ factor = make_float3((steps.x > 0.0f) ? floorf(factor.x * (steps.x + 1.0f)) / steps.x : 0.0f,
+ (steps.y > 0.0f) ? floorf(factor.y * (steps.y + 1.0f)) / steps.y : 0.0f,
+ (steps.z > 0.0f) ? floorf(factor.z * (steps.z + 1.0f)) / steps.z :
+ 0.0f);
+ break;
+ }
+ case NODE_MAP_RANGE_SMOOTHSTEP: {
+ factor = safe_divide_float3_float3((value - from_min), (from_max - from_min));
+ factor = clamp(factor, zero_float3(), one_float3());
+ factor = (make_float3(3.0f, 3.0f, 3.0f) - 2.0f * factor) * (factor * factor);
+ break;
+ }
+ case NODE_MAP_RANGE_SMOOTHERSTEP: {
+ factor = safe_divide_float3_float3((value - from_min), (from_max - from_min));
+ factor = clamp(factor, zero_float3(), one_float3());
+ factor = factor * factor * factor * (factor * (factor * 6.0f - 15.0f) + 10.0f);
+ break;
+ }
+ }
+ result = to_min + factor * (to_max - to_min);
+ if (use_clamp > 0) {
+ result.x = (to_min.x > to_max.x) ? clamp(result.x, to_max.x, to_min.x) :
+ clamp(result.x, to_min.x, to_max.x);
+ result.y = (to_min.y > to_max.y) ? clamp(result.y, to_max.y, to_min.y) :
+ clamp(result.y, to_min.y, to_max.y);
+ result.z = (to_min.z > to_max.z) ? clamp(result.z, to_max.z, to_min.z) :
+ clamp(result.z, to_min.z, to_max.z);
+ }
+
+ stack_store_float3(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..20817cd0fd3
--- /dev/null
+++ b/intern/cycles/kernel/svm/math_util.h
@@ -0,0 +1,258 @@
+/*
+ * 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.
+ */
+
+ 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..a37ca9eb8eb
--- /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, 15.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 4aee1ef11b3..35d4c3f2055 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,62 +37,62 @@
* mostly taken care of in the SVM compiler.
*/
-#include "kernel/svm/svm_types.h"
+#include "kernel/svm/types.h"
CCL_NAMESPACE_BEGIN
/* Stack */
-ccl_device_inline float3 stack_load_float3(float *stack, uint a)
+ccl_device_inline float3 stack_load_float3(ccl_private float *stack, uint a)
{
kernel_assert(a + 2 < SVM_STACK_SIZE);
- float *stack_a = stack + a;
+ ccl_private float *stack_a = stack + a;
return make_float3(stack_a[0], stack_a[1], stack_a[2]);
}
-ccl_device_inline void stack_store_float3(float *stack, uint a, float3 f)
+ccl_device_inline void stack_store_float3(ccl_private float *stack, uint a, float3 f)
{
kernel_assert(a + 2 < SVM_STACK_SIZE);
- float *stack_a = stack + a;
+ ccl_private float *stack_a = stack + a;
stack_a[0] = f.x;
stack_a[1] = f.y;
stack_a[2] = f.z;
}
-ccl_device_inline float stack_load_float(float *stack, uint a)
+ccl_device_inline float stack_load_float(ccl_private float *stack, uint a)
{
kernel_assert(a < SVM_STACK_SIZE);
return stack[a];
}
-ccl_device_inline float stack_load_float_default(float *stack, uint a, uint value)
+ccl_device_inline float stack_load_float_default(ccl_private float *stack, uint a, uint value)
{
return (a == (uint)SVM_STACK_INVALID) ? __uint_as_float(value) : stack_load_float(stack, a);
}
-ccl_device_inline void stack_store_float(float *stack, uint a, float f)
+ccl_device_inline void stack_store_float(ccl_private float *stack, uint a, float f)
{
kernel_assert(a < SVM_STACK_SIZE);
stack[a] = f;
}
-ccl_device_inline int stack_load_int(float *stack, uint a)
+ccl_device_inline int stack_load_int(ccl_private float *stack, uint a)
{
kernel_assert(a < SVM_STACK_SIZE);
return __float_as_int(stack[a]);
}
-ccl_device_inline int stack_load_int_default(float *stack, uint a, uint value)
+ccl_device_inline int stack_load_int_default(ccl_private float *stack, uint a, uint value)
{
return (a == (uint)SVM_STACK_INVALID) ? (int)value : stack_load_int(stack, a);
}
-ccl_device_inline void stack_store_int(float *stack, uint a, int i)
+ccl_device_inline void stack_store_int(ccl_private float *stack, uint a, int i)
{
kernel_assert(a < SVM_STACK_SIZE);
@@ -107,14 +106,14 @@ ccl_device_inline bool stack_valid(uint a)
/* Reading Nodes */
-ccl_device_inline uint4 read_node(const KernelGlobals *kg, int *offset)
+ccl_device_inline uint4 read_node(KernelGlobals kg, ccl_private int *offset)
{
uint4 node = kernel_tex_fetch(__svm_nodes, *offset);
(*offset)++;
return node;
}
-ccl_device_inline float4 read_node_float(const KernelGlobals *kg, int *offset)
+ccl_device_inline float4 read_node_float(KernelGlobals kg, ccl_private int *offset)
{
uint4 node = kernel_tex_fetch(__svm_nodes, *offset);
float4 f = make_float4(__uint_as_float(node.x),
@@ -125,7 +124,7 @@ ccl_device_inline float4 read_node_float(const KernelGlobals *kg, int *offset)
return f;
}
-ccl_device_inline float4 fetch_node_float(const KernelGlobals *kg, int offset)
+ccl_device_inline float4 fetch_node_float(KernelGlobals kg, int offset)
{
uint4 node = kernel_tex_fetch(__svm_nodes, offset);
return make_float4(__uint_as_float(node.x),
@@ -134,20 +133,26 @@ ccl_device_inline float4 fetch_node_float(const KernelGlobals *kg, int offset)
__uint_as_float(node.w));
}
-ccl_device_forceinline void svm_unpack_node_uchar2(uint i, uint *x, uint *y)
+ccl_device_forceinline void svm_unpack_node_uchar2(uint i,
+ ccl_private uint *x,
+ ccl_private uint *y)
{
*x = (i & 0xFF);
*y = ((i >> 8) & 0xFF);
}
-ccl_device_forceinline void svm_unpack_node_uchar3(uint i, uint *x, uint *y, uint *z)
+ccl_device_forceinline void svm_unpack_node_uchar3(uint i,
+ ccl_private uint *x,
+ ccl_private uint *y,
+ ccl_private uint *z)
{
*x = (i & 0xFF);
*y = ((i >> 8) & 0xFF);
*z = ((i >> 16) & 0xFF);
}
-ccl_device_forceinline void svm_unpack_node_uchar4(uint i, uint *x, uint *y, uint *z, uint *w)
+ccl_device_forceinline void svm_unpack_node_uchar4(
+ uint i, ccl_private uint *x, ccl_private uint *y, ccl_private uint *z, ccl_private uint *w)
{
*x = (i & 0xFF);
*y = ((i >> 8) & 0xFF);
@@ -159,71 +164,65 @@ 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
/* Main Interpreter Loop */
-template<uint node_feature_mask, ShaderType type>
-ccl_device void svm_eval_nodes(INTEGRATOR_STATE_CONST_ARGS,
- ShaderData *sd,
+template<uint node_feature_mask, ShaderType type, typename ConstIntegratorGenericState>
+ccl_device void svm_eval_nodes(KernelGlobals kg,
+ ConstIntegratorGenericState state,
+ ccl_private ShaderData *sd,
ccl_global float *render_buffer,
- int path_flag)
+ uint32_t path_flag)
{
float stack[SVM_STACK_SIZE];
int offset = sd->shader & SHADER_MASK;
@@ -250,12 +249,14 @@ ccl_device void svm_eval_nodes(INTEGRATOR_STATE_CONST_ARGS,
kg, sd, stack, node, path_flag, offset);
break;
case NODE_CLOSURE_EMISSION:
- if (KERNEL_NODES_FEATURE(EMISSION)) {
+ IF_KERNEL_NODES_FEATURE(EMISSION)
+ {
svm_node_closure_emission(sd, stack, node);
}
break;
case NODE_CLOSURE_BACKGROUND:
- if (KERNEL_NODES_FEATURE(EMISSION)) {
+ IF_KERNEL_NODES_FEATURE(EMISSION)
+ {
svm_node_closure_background(sd, stack, node);
}
break;
@@ -266,7 +267,8 @@ ccl_device void svm_eval_nodes(INTEGRATOR_STATE_CONST_ARGS,
svm_node_closure_weight(sd, stack, node.y);
break;
case NODE_EMISSION_WEIGHT:
- if (KERNEL_NODES_FEATURE(EMISSION)) {
+ IF_KERNEL_NODES_FEATURE(EMISSION)
+ {
svm_node_emission_weight(kg, sd, stack, node);
}
break;
@@ -303,27 +305,32 @@ ccl_device void svm_eval_nodes(INTEGRATOR_STATE_CONST_ARGS,
svm_node_vertex_color(kg, sd, stack, node.y, node.z, node.w);
break;
case NODE_GEOMETRY_BUMP_DX:
- if (KERNEL_NODES_FEATURE(BUMP)) {
+ IF_KERNEL_NODES_FEATURE(BUMP)
+ {
svm_node_geometry_bump_dx(kg, sd, stack, node.y, node.z);
}
break;
case NODE_GEOMETRY_BUMP_DY:
- if (KERNEL_NODES_FEATURE(BUMP)) {
+ IF_KERNEL_NODES_FEATURE(BUMP)
+ {
svm_node_geometry_bump_dy(kg, sd, stack, node.y, node.z);
}
break;
case NODE_SET_DISPLACEMENT:
- if (KERNEL_NODES_FEATURE(BUMP)) {
+ IF_KERNEL_NODES_FEATURE(BUMP)
+ {
svm_node_set_displacement(kg, sd, stack, node.y);
}
break;
case NODE_DISPLACEMENT:
- if (KERNEL_NODES_FEATURE(BUMP)) {
+ IF_KERNEL_NODES_FEATURE(BUMP)
+ {
svm_node_displacement(kg, sd, stack, node);
}
break;
case NODE_VECTOR_DISPLACEMENT:
- if (KERNEL_NODES_FEATURE(BUMP)) {
+ IF_KERNEL_NODES_FEATURE(BUMP)
+ {
offset = svm_node_vector_displacement(kg, sd, stack, node, offset);
}
break;
@@ -337,52 +344,62 @@ ccl_device void svm_eval_nodes(INTEGRATOR_STATE_CONST_ARGS,
offset = svm_node_tex_noise(kg, sd, stack, node.y, node.z, node.w, offset);
break;
case NODE_SET_BUMP:
- if (KERNEL_NODES_FEATURE(BUMP)) {
+ IF_KERNEL_NODES_FEATURE(BUMP)
+ {
svm_node_set_bump(kg, sd, stack, node);
}
break;
case NODE_ATTR_BUMP_DX:
- if (KERNEL_NODES_FEATURE(BUMP)) {
+ IF_KERNEL_NODES_FEATURE(BUMP)
+ {
svm_node_attr_bump_dx(kg, sd, stack, node);
}
break;
case NODE_ATTR_BUMP_DY:
- if (KERNEL_NODES_FEATURE(BUMP)) {
+ IF_KERNEL_NODES_FEATURE(BUMP)
+ {
svm_node_attr_bump_dy(kg, sd, stack, node);
}
break;
case NODE_VERTEX_COLOR_BUMP_DX:
- if (KERNEL_NODES_FEATURE(BUMP)) {
+ IF_KERNEL_NODES_FEATURE(BUMP)
+ {
svm_node_vertex_color_bump_dx(kg, sd, stack, node.y, node.z, node.w);
}
break;
case NODE_VERTEX_COLOR_BUMP_DY:
- if (KERNEL_NODES_FEATURE(BUMP)) {
+ IF_KERNEL_NODES_FEATURE(BUMP)
+ {
svm_node_vertex_color_bump_dy(kg, sd, stack, node.y, node.z, node.w);
}
break;
case NODE_TEX_COORD_BUMP_DX:
- if (KERNEL_NODES_FEATURE(BUMP)) {
+ IF_KERNEL_NODES_FEATURE(BUMP)
+ {
offset = svm_node_tex_coord_bump_dx(kg, sd, path_flag, stack, node, offset);
}
break;
case NODE_TEX_COORD_BUMP_DY:
- if (KERNEL_NODES_FEATURE(BUMP)) {
+ IF_KERNEL_NODES_FEATURE(BUMP)
+ {
offset = svm_node_tex_coord_bump_dy(kg, sd, path_flag, stack, node, offset);
}
break;
case NODE_CLOSURE_SET_NORMAL:
- if (KERNEL_NODES_FEATURE(BUMP)) {
+ IF_KERNEL_NODES_FEATURE(BUMP)
+ {
svm_node_set_normal(kg, sd, stack, node.y, node.z);
}
break;
case NODE_ENTER_BUMP_EVAL:
- if (KERNEL_NODES_FEATURE(BUMP_STATE)) {
+ IF_KERNEL_NODES_FEATURE(BUMP_STATE)
+ {
svm_node_enter_bump_eval(kg, sd, stack, node.y);
}
break;
case NODE_LEAVE_BUMP_EVAL:
- if (KERNEL_NODES_FEATURE(BUMP_STATE)) {
+ IF_KERNEL_NODES_FEATURE(BUMP_STATE)
+ {
svm_node_leave_bump_eval(kg, sd, stack, node.y);
}
break;
@@ -400,12 +417,14 @@ ccl_device void svm_eval_nodes(INTEGRATOR_STATE_CONST_ARGS,
svm_node_layer_weight(sd, stack, node);
break;
case NODE_CLOSURE_VOLUME:
- if (KERNEL_NODES_FEATURE(VOLUME)) {
+ IF_KERNEL_NODES_FEATURE(VOLUME)
+ {
svm_node_closure_volume<type>(kg, sd, stack, node);
}
break;
case NODE_PRINCIPLED_VOLUME:
- if (KERNEL_NODES_FEATURE(VOLUME)) {
+ IF_KERNEL_NODES_FEATURE(VOLUME)
+ {
offset = svm_node_principled_volume<type>(kg, sd, stack, node, path_flag, offset);
}
break;
@@ -425,7 +444,7 @@ ccl_device void svm_eval_nodes(INTEGRATOR_STATE_CONST_ARGS,
svm_node_brightness(sd, stack, node.y, node.z, node.w);
break;
case NODE_LIGHT_PATH:
- svm_node_light_path(INTEGRATOR_STATE_PASS, sd, stack, node.y, node.z, path_flag);
+ svm_node_light_path<node_feature_mask>(kg, state, sd, stack, node.y, node.z, path_flag);
break;
case NODE_OBJECT_INFO:
svm_node_object_info(kg, sd, stack, node.y, node.z);
@@ -435,12 +454,14 @@ ccl_device void svm_eval_nodes(INTEGRATOR_STATE_CONST_ARGS,
break;
#if defined(__HAIR__)
case NODE_HAIR_INFO:
- if (KERNEL_NODES_FEATURE(HAIR)) {
- svm_node_hair_info(kg, sd, stack, node.y, node.z);
- }
+ svm_node_hair_info(kg, sd, stack, node.y, node.z);
+ break;
+#endif
+#if defined(__POINTCLOUD__)
+ case NODE_POINT_INFO:
+ svm_node_point_info(kg, sd, stack, node.y, node.z);
break;
#endif
-
case NODE_TEXTURE_MAPPING:
offset = svm_node_texture_mapping(kg, sd, stack, node.y, node.z, offset);
break;
@@ -493,11 +514,13 @@ ccl_device void svm_eval_nodes(INTEGRATOR_STATE_CONST_ARGS,
case NODE_IES:
svm_node_ies(kg, sd, stack, node);
break;
-
case NODE_RGB_CURVES:
case NODE_VECTOR_CURVES:
offset = svm_node_curves(kg, sd, stack, node, offset);
break;
+ case NODE_FLOAT_CURVE:
+ offset = svm_node_curve(kg, sd, stack, node, offset);
+ break;
case NODE_TANGENT:
svm_node_tangent(kg, sd, stack, node);
break;
@@ -540,20 +563,24 @@ ccl_device void svm_eval_nodes(INTEGRATOR_STATE_CONST_ARGS,
case NODE_MAP_RANGE:
offset = svm_node_map_range(kg, sd, stack, node.y, node.z, node.w, offset);
break;
+ case NODE_VECTOR_MAP_RANGE:
+ offset = svm_node_vector_map_range(kg, sd, stack, node.y, node.z, node.w, offset);
+ break;
case NODE_CLAMP:
offset = svm_node_clamp(kg, sd, stack, node.y, node.z, node.w, offset);
break;
#ifdef __SHADER_RAYTRACE__
case NODE_BEVEL:
- svm_node_bevel<node_feature_mask>(INTEGRATOR_STATE_PASS, sd, stack, node);
+ svm_node_bevel<node_feature_mask>(kg, state, sd, stack, node);
break;
case NODE_AMBIENT_OCCLUSION:
- svm_node_ao<node_feature_mask>(INTEGRATOR_STATE_PASS, sd, stack, node);
+ svm_node_ao<node_feature_mask>(kg, state, sd, stack, node);
break;
#endif
case NODE_TEX_VOXEL:
- if (KERNEL_NODES_FEATURE(VOLUME)) {
+ IF_KERNEL_NODES_FEATURE(VOLUME)
+ {
offset = svm_node_tex_voxel(kg, sd, stack, node, offset);
}
break;
@@ -563,10 +590,10 @@ ccl_device void svm_eval_nodes(INTEGRATOR_STATE_CONST_ARGS,
}
break;
case NODE_AOV_COLOR:
- svm_node_aov_color(INTEGRATOR_STATE_PASS, sd, stack, node, render_buffer);
+ svm_node_aov_color<node_feature_mask>(kg, state, sd, stack, node, render_buffer);
break;
case NODE_AOV_VALUE:
- svm_node_aov_value(INTEGRATOR_STATE_PASS, sd, stack, node, render_buffer);
+ svm_node_aov_value<node_feature_mask>(kg, state, sd, stack, node, render_buffer);
break;
default:
kernel_assert(!"Unknown node type was passed to the SVM machine");
@@ -576,5 +603,3 @@ ccl_device void svm_eval_nodes(INTEGRATOR_STATE_CONST_ARGS,
}
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 34ac2cb8fbf..00000000000
--- a/intern/cycles/kernel/svm/svm_ao.h
+++ /dev/null
@@ -1,132 +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(INTEGRATOR_STATE_CONST_ARGS,
-# else
-ccl_device float svm_ao(INTEGRATOR_STATE_CONST_ARGS,
-# endif
- 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(INTEGRATOR_STATE_PASS, &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>
-# if defined(__KERNEL_OPTIX__)
-ccl_device_inline
-# else
-ccl_device_noinline
-# endif
- void
- svm_node_ao(INTEGRATOR_STATE_CONST_ARGS, ShaderData *sd, 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 dist = stack_load_float_default(stack, dist_offset, node.w);
- float3 normal = stack_valid(normal_offset) ? stack_load_float3(stack, normal_offset) : sd->N;
-
- float ao = 1.0f;
-
- if (KERNEL_NODES_FEATURE(RAYTRACE)) {
-# ifdef __KERNEL_OPTIX__
- ao = optixDirectCall<float>(0, INTEGRATOR_STATE_PASS, sd, normal, dist, samples, flags);
-# else
- ao = svm_ao(INTEGRATOR_STATE_PASS, 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 26dec9717b3..00000000000
--- a/intern/cycles/kernel/svm/svm_aov.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.
- */
-
-#include "kernel/kernel_write_passes.h"
-
-CCL_NAMESPACE_BEGIN
-
-ccl_device_inline bool svm_node_aov_check(const int 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);
-}
-
-ccl_device void svm_node_aov_color(INTEGRATOR_STATE_CONST_ARGS,
- ShaderData *sd,
- float *stack,
- uint4 node,
- ccl_global float *render_buffer)
-{
- float3 val = stack_load_float3(stack, node.y);
-
- if (render_buffer && !INTEGRATOR_STATE_IS_NULL) {
- const uint32_t render_pixel_index = INTEGRATOR_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));
- }
-}
-
-ccl_device void svm_node_aov_value(INTEGRATOR_STATE_CONST_ARGS,
- ShaderData *sd,
- float *stack,
- uint4 node,
- ccl_global float *render_buffer)
-{
- float val = stack_load_float(stack, node.y);
-
- if (render_buffer && !INTEGRATOR_STATE_IS_NULL) {
- const uint32_t render_pixel_index = INTEGRATOR_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 5f94b20af73..00000000000
--- a/intern/cycles/kernel/svm/svm_attribute.h
+++ /dev/null
@@ -1,343 +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(const KernelGlobals *kg,
- ShaderData *sd,
- uint4 node,
- NodeAttributeOutputType *type,
- 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(const KernelGlobals *kg,
- ShaderData *sd,
- 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(const KernelGlobals *kg,
- ShaderData *sd,
- 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(const KernelGlobals *kg,
- ShaderData *sd,
- 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 9d7ce202d49..00000000000
--- a/intern/cycles/kernel/svm/svm_bevel.h
+++ /dev/null
@@ -1,318 +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, float *r, 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(INTEGRATOR_STATE_CONST_ARGS,
-# else
-ccl_device float3 svm_bevel(INTEGRATOR_STATE_CONST_ARGS,
-# endif
- 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(path, min_ray_pdf) < 8.0f) {
- return sd->N;
- }
-
- /* Setup for multi intersection. */
- LocalIntersection isect;
- uint lcg_state = lcg_state_init(INTEGRATOR_STATE(path, rng_hash),
- INTEGRATOR_STATE(path, rng_offset),
- INTEGRATOR_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(INTEGRATOR_STATE_PASS, &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 = &isect.ray;
- 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, kernel_tex_fetch(__prim_index, 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 == OBJECT_NONE) ?
- kernel_tex_fetch(__prim_object, isect.hits[hit].prim) :
- 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 = kernel_tex_fetch(__prim_index, 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>
-# if defined(__KERNEL_OPTIX__)
-ccl_device_inline
-# else
-ccl_device_noinline
-# endif
- void
- svm_node_bevel(INTEGRATOR_STATE_CONST_ARGS, ShaderData *sd, 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);
-
- float radius = stack_load_float(stack, radius_offset);
-
- float3 bevel_N = sd->N;
-
- if (KERNEL_NODES_FEATURE(RAYTRACE)) {
-# ifdef __KERNEL_OPTIX__
- bevel_N = optixDirectCall<float3>(1, INTEGRATOR_STATE_PASS, sd, radius, num_samples);
-# else
- bevel_N = svm_bevel(INTEGRATOR_STATE_PASS, 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 96b3703b954..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(const KernelGlobals *kg,
- ShaderData *sd,
- 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 dca1b220dd5..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(
- const KernelGlobals *kg, ShaderData *sd, 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 2ed812acd71..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(
- ShaderData *sd, 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 8672839dbab..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(const KernelGlobals *kg,
- ShaderData *sd,
- 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(const KernelGlobals *kg,
- ShaderData *sd,
- 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 40c0edcdad0..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(const KernelGlobals *kg,
- ShaderData *sd,
- 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 a9919c9ddc9..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(const KernelGlobals *kg,
- ShaderData *sd,
- 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 656bd31c085..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(const KernelGlobals *kg,
- ShaderData *sd,
- 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 e2f6dde4ace..00000000000
--- a/intern/cycles/kernel/svm/svm_closure.h
+++ /dev/null
@@ -1,1199 +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(
- ShaderData *sd, 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);
- }
-}
-
-template<uint node_feature_mask, ShaderType shader_type>
-ccl_device_noinline int svm_node_closure_bsdf(
- const KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int 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) || shader_type != SHADER_TYPE_SURFACE) || mix_weight == 0.0f) {
- 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;
- }
-
- float3 N = stack_valid(data_node.x) ? stack_load_float3(stack, data_node.x) : sd->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;
- 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;
-
- PrincipledDiffuseBsdf *bsdf = (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);
- }
- }
- else if (subsurface > CLOSURE_WEIGHT_CUTOFF) {
- 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;
-
- PrincipledDiffuseBsdf *bsdf = (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);
- }
- }
-# 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;
-
- PrincipledSheenBsdf *bsdf = (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;
-
- MicrofacetBsdf *bsdf = (MicrofacetBsdf *)bsdf_alloc(
- sd, sizeof(MicrofacetBsdf), spec_weight);
- MicrofacetExtra *extra = (bsdf != NULL) ? (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
- {
- MicrofacetBsdf *bsdf = (MicrofacetBsdf *)bsdf_alloc(
- sd, sizeof(MicrofacetBsdf), glass_weight * fresnel);
- MicrofacetExtra *extra = (bsdf != NULL) ? (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
- {
- MicrofacetBsdf *bsdf = (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 */
- MicrofacetBsdf *bsdf = (MicrofacetBsdf *)bsdf_alloc(
- sd, sizeof(MicrofacetBsdf), glass_weight);
- MicrofacetExtra *extra = (bsdf != NULL) ? (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) {
- MicrofacetBsdf *bsdf = (MicrofacetBsdf *)bsdf_alloc(sd, sizeof(MicrofacetBsdf), weight);
- MicrofacetExtra *extra = (bsdf != NULL) ? (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;
- OrenNayarBsdf *bsdf = (OrenNayarBsdf *)bsdf_alloc(sd, sizeof(OrenNayarBsdf), weight);
-
- if (bsdf) {
- bsdf->N = N;
-
- float roughness = param1;
-
- if (roughness == 0.0f) {
- sd->flag |= bsdf_diffuse_setup((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;
- DiffuseBsdf *bsdf = (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;
- MicrofacetBsdf *bsdf = (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 = (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;
- MicrofacetBsdf *bsdf = (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
- {
- MicrofacetBsdf *bsdf = (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
- {
- MicrofacetBsdf *bsdf = (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;
- MicrofacetBsdf *bsdf = (MicrofacetBsdf *)bsdf_alloc(sd, sizeof(MicrofacetBsdf), weight);
- if (!bsdf) {
- break;
- }
-
- MicrofacetExtra *extra = (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;
- VelvetBsdf *bsdf = (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;
- ToonBsdf *bsdf = (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);
- }
-
- PrincipledHairBSDF *bsdf = (PrincipledHairBSDF *)bsdf_alloc(
- sd, sizeof(PrincipledHairBSDF), weight);
- if (bsdf) {
- PrincipledHairExtra *extra = (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;
-
- HairBsdf *bsdf = (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_RANDOM_WALK_ID:
- case CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID: {
- float3 weight = sd->svm_closure_weight * mix_weight;
- 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(const KernelGlobals *kg,
- ShaderData *sd,
- 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) {
- HenyeyGreensteinVolume *volume = (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(
- const KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int 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. */
- HenyeyGreensteinVolume *volume = (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(ShaderData *sd, 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(ShaderData *sd, 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(ShaderData *sd, 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(ShaderData *sd, float3 weight)
-{
- sd->svm_closure_weight = weight;
-}
-
-ccl_device void svm_node_closure_set_weight(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(ShaderData *sd, 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(const KernelGlobals *kg,
- ShaderData *sd,
- 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(ShaderData *sd, 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(
- const KernelGlobals *kg, ShaderData *sd, 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 37d40167ccc..00000000000
--- a/intern/cycles/kernel/svm/svm_convert.h
+++ /dev/null
@@ -1,72 +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(
- const KernelGlobals *kg, ShaderData *sd, 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 a1d952173d8..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(const KernelGlobals *kg,
- ShaderData *sd,
- 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(const KernelGlobals *kg,
- ShaderData *sd,
- float *stack,
- uint fac_offset)
-{
- float3 dP = stack_load_float3(stack, fac_offset);
- sd->P += dP;
-}
-
-ccl_device_noinline void svm_node_displacement(const KernelGlobals *kg,
- ShaderData *sd,
- 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(
- const KernelGlobals *kg, ShaderData *sd, 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 b5ecdbe2abf..00000000000
--- a/intern/cycles/kernel/svm/svm_fresnel.h
+++ /dev/null
@@ -1,77 +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(
- ShaderData *sd, 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(ShaderData *sd, 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 f6fafdee941..00000000000
--- a/intern/cycles/kernel/svm/svm_gamma.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.
- */
-
-CCL_NAMESPACE_BEGIN
-
-ccl_device_noinline void svm_node_gamma(
- ShaderData *sd, 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 432529eb061..00000000000
--- a/intern/cycles/kernel/svm/svm_geometry.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.
- */
-
-CCL_NAMESPACE_BEGIN
-
-/* Geometry Node */
-
-ccl_device_noinline void svm_node_geometry(
- const KernelGlobals *kg, ShaderData *sd, 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(
- const KernelGlobals *kg, ShaderData *sd, 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(
- const KernelGlobals *kg, ShaderData *sd, 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(
- const KernelGlobals *kg, ShaderData *sd, 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(
- const KernelGlobals *kg, ShaderData *sd, 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(
- const KernelGlobals *kg, ShaderData *sd, 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 cd15f7097e7..00000000000
--- a/intern/cycles/kernel/svm/svm_gradient.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
-
-/* 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(ShaderData *sd, 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 6f49a8385aa..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(const KernelGlobals *kg,
- ShaderData *sd,
- 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 9c13734ecf0..00000000000
--- a/intern/cycles/kernel/svm/svm_ies.h
+++ /dev/null
@@ -1,123 +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(
- const 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(const 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(const KernelGlobals *kg,
- ShaderData *sd,
- 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 a344f36977a..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(const 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(
- const KernelGlobals *kg, ShaderData *sd, 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(const KernelGlobals *kg,
- ShaderData *sd,
- 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(const KernelGlobals *kg,
- ShaderData *sd,
- 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 27cdaaff473..00000000000
--- a/intern/cycles/kernel/svm/svm_invert.h
+++ /dev/null
@@ -1,38 +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(
- ShaderData *sd, 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 49fabad1cc5..00000000000
--- a/intern/cycles/kernel/svm/svm_light_path.h
+++ /dev/null
@@ -1,142 +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 */
-
-ccl_device_noinline void svm_node_light_path(INTEGRATOR_STATE_CONST_ARGS,
- const ShaderData *sd,
- float *stack,
- uint type,
- uint out_offset,
- int 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. */
- int bounce = (INTEGRATOR_STATE_IS_NULL) ? 0 :
- (path_flag & PATH_RAY_SHADOW) ? INTEGRATOR_STATE(shadow_path, bounce) :
- INTEGRATOR_STATE(path, bounce);
-
- /* 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)) {
- bounce++;
- }
-
- info = (float)bounce;
- break;
- }
- /* TODO */
- case NODE_LP_ray_transparent: {
- const int bounce = (INTEGRATOR_STATE_IS_NULL) ?
- 0 :
- (path_flag & PATH_RAY_SHADOW) ?
- INTEGRATOR_STATE(shadow_path, transparent_bounce) :
- INTEGRATOR_STATE(path, transparent_bounce);
-
- info = (float)bounce;
- break;
- }
-#if 0
- case NODE_LP_ray_diffuse:
- info = (float)state->diffuse_bounce;
- break;
- case NODE_LP_ray_glossy:
- info = (float)state->glossy_bounce;
- break;
-#endif
-#if 0
- case NODE_LP_ray_transmission:
- info = (float)state->transmission_bounce;
- break;
-#endif
- }
-
- stack_store_float(stack, out_offset, info);
-}
-
-/* Light Falloff Node */
-
-ccl_device_noinline void svm_node_light_falloff(ShaderData *sd, 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 8784c760860..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(
- const KernelGlobals *kg, ShaderData *sd, 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 c8684981e31..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(const KernelGlobals *kg,
- ShaderData *sd,
- 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 fcc724405f5..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(const KernelGlobals *kg,
- ShaderData *sd,
- 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(const KernelGlobals *kg,
- ShaderData *sd,
- 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(const KernelGlobals *kg,
- ShaderData *sd,
- 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 99e7a8f2bda..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(const KernelGlobals *kg,
- ShaderData *sd,
- 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(const KernelGlobals *kg,
- ShaderData *sd,
- 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 9e654f2247f..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(float *value,
- 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;
- }
-}
-
-/* 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.
- */
-
-ccl_static_constant 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},
-};
-
-ccl_static_constant 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},
-};
-
-ccl_static_constant 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},
-};
-
-ccl_device float3 svm_math_blackbody_color(float t)
-{
- /* TODO(lukas): Reimplement in XYZ. */
-
- 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 3e38080977f..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(const KernelGlobals *kg,
- ShaderData *sd,
- 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 03a8b68b3ef..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(const KernelGlobals *kg,
- ShaderData *sd,
- 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 29b262ac06e..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,
- float *value,
- 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,
- float *value,
- 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,
- float *value,
- 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,
- float *value,
- 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(const KernelGlobals *kg,
- ShaderData *sd,
- 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 724b5f281f9..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(const KernelGlobals *kg,
- ShaderData *sd,
- 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 e92df3c093c..00000000000
--- a/intern/cycles/kernel/svm/svm_ramp.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 __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 float4 rgb_ramp_lookup(const 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(
- const KernelGlobals *kg, ShaderData *sd, 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(
- const KernelGlobals *kg, ShaderData *sd, 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_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 8d52845ea3d..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(const KernelGlobals *kg,
- ShaderData *sd,
- 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(const KernelGlobals *kg,
- ShaderData *sd,
- 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 cbf77f1e640..00000000000
--- a/intern/cycles/kernel/svm/svm_sepcomb_vector.h
+++ /dev/null
@@ -1,45 +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(
- ShaderData *sd, 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(
- ShaderData *sd, 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 b77c4311e72..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(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(const KernelGlobals *kg,
- float3 dir,
- float sunphi,
- float suntheta,
- float radiance_x,
- float radiance_y,
- float radiance_z,
- float *config_x,
- float *config_y,
- 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(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(const KernelGlobals *kg,
- float3 dir,
- float sunphi,
- float suntheta,
- float radiance_x,
- float radiance_y,
- float radiance_z,
- float *config_x,
- float *config_y,
- 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(const KernelGlobals *kg,
- float3 dir,
- 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(
- const KernelGlobals *kg, ShaderData *sd, 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 a35253080da..00000000000
--- a/intern/cycles/kernel/svm/svm_tex_coord.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.
- */
-
-#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(
- const KernelGlobals *kg, ShaderData *sd, int path_flag, 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(
- const KernelGlobals *kg, ShaderData *sd, int path_flag, 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(
- const KernelGlobals *kg, ShaderData *sd, int path_flag, 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(const KernelGlobals *kg,
- ShaderData *sd,
- 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);
- }
-
- N = ensure_valid_reflection(sd->Ng, sd->I, N);
-
- if (is_zero(N)) {
- N = sd->N;
- }
-
- stack_store_float3(stack, normal_offset, N);
-}
-
-ccl_device_noinline void svm_node_tangent(const KernelGlobals *kg,
- ShaderData *sd,
- 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 313bc3235b9..00000000000
--- a/intern/cycles/kernel/svm/svm_types.h
+++ /dev/null
@@ -1,606 +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,
- /* 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_BSSRDF_ID,
- CLOSURE_BSDF_BSSRDF_PRINCIPLED_ID,
- CLOSURE_BSDF_TRANSPARENT_ID,
-
- /* BSSRDF */
- 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_BSSRDF(type) \
- (type == CLOSURE_BSDF_BSSRDF_ID || type == CLOSURE_BSDF_BSSRDF_PRINCIPLED_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_RANDOM_WALK_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 d0478660094..00000000000
--- a/intern/cycles/kernel/svm/svm_value.h
+++ /dev/null
@@ -1,39 +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(
- const KernelGlobals *kg, ShaderData *sd, float *stack, uint ivalue, uint out_offset)
-{
- stack_store_float(stack, out_offset, __uint_as_float(ivalue));
-}
-
-ccl_device int svm_node_value_v(
- const KernelGlobals *kg, ShaderData *sd, 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 55e1bce0158..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(ShaderData *sd,
- 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 8aedb7e0f54..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(const KernelGlobals *kg,
- ShaderData *sd,
- 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 986ea244f3a..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(const KernelGlobals *kg,
- ShaderData *sd,
- 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(const KernelGlobals *kg,
- ShaderData *sd,
- 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(const KernelGlobals *kg,
- ShaderData *sd,
- 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 b1d2eff7f37..00000000000
--- a/intern/cycles/kernel/svm/svm_voronoi.h
+++ /dev/null
@@ -1,1145 +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,
- float *outDistance,
- float3 *outColor,
- 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,
- float *outDistance,
- float3 *outColor,
- 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,
- float *outDistance,
- float3 *outColor,
- 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, 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, 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,
- float *outDistance,
- float3 *outColor,
- 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,
- float *outDistance,
- float3 *outColor,
- 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,
- float *outDistance,
- float3 *outColor,
- 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, 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, 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,
- float *outDistance,
- float3 *outColor,
- 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,
- float *outDistance,
- float3 *outColor,
- 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,
- float *outDistance,
- float3 *outColor,
- 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, 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, 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,
- float *outDistance,
- float3 *outColor,
- 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,
- float *outDistance,
- float3 *outColor,
- 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,
- float *outDistance,
- float3 *outColor,
- 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, 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, 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(const KernelGlobals *kg,
- ShaderData *sd,
- 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;
- 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 78b75405356..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(
- const KernelGlobals *kg, ShaderData *sd, 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 00f980c16df..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(
- const KernelGlobals *kg, ShaderData *sd, 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 fba8aa63d31..00000000000
--- a/intern/cycles/kernel/svm/svm_wavelength.h
+++ /dev/null
@@ -1,98 +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 */
-
-// 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
-ccl_static_constant 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}};
-
-ccl_device_noinline void svm_node_wavelength(
- const KernelGlobals *kg, ShaderData *sd, float *stack, uint wavelength, uint color_out)
-{
- 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 0306d2e7b9c..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(const KernelGlobals *kg,
- ShaderData *sd,
- 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 7ec913789d2..00000000000
--- a/intern/cycles/kernel/svm/svm_wireframe.h
+++ /dev/null
@@ -1,122 +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(
- const KernelGlobals *kg, ShaderData *sd, float size, int pixel_size, 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(const KernelGlobals *kg,
- ShaderData *sd,
- 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..4b12a0065a6
--- /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_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..16e9fd8862a
--- /dev/null
+++ b/intern/cycles/kernel/svm/types.h
@@ -0,0 +1,607 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_POINT_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_VECTOR_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,
+ NODE_INFO_CURVE_TANGENT_NORMAL,
+ NODE_INFO_CURVE_RANDOM,
+} NodeHairInfo;
+
+typedef enum NodePointInfo {
+ NODE_INFO_POINT_POSITION,
+ NODE_INFO_POINT_RADIUS,
+ NODE_INFO_POINT_RANDOM,
+} NodePointInfo;
+
+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..6e25224243f
--- /dev/null
+++ b/intern/cycles/kernel/svm/wavelength.h
@@ -0,0 +1,68 @@
+/*
+ * 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)
+{
+ 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..2c91ab3dedf
--- /dev/null
+++ b/intern/cycles/kernel/svm/wireframe.h
@@ -0,0 +1,129 @@
+/*
+ * 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)
+{
+#if defined(__HAIR__) || defined(__POINTCLOUD__)
+ if (sd->prim != PRIM_NONE && sd->type & PRIMITIVE_TRIANGLE)
+#else
+ if (sd->prim != PRIM_NONE)
+#endif
+ {
+ float3 Co[3];
+ float pixelwidth = 1.0f;
+
+ /* Triangles */
+ int np = 3;
+
+ if (sd->type & PRIMITIVE_MOTION) {
+ motion_triangle_vertices(kg, sd->object, sd->prim, sd->time, Co);
+ }
+ else {
+ triangle_vertices(kg, sd->prim, 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/tables.h b/intern/cycles/kernel/tables.h
new file mode 100644
index 00000000000..544bf7b7add
--- /dev/null
+++ b/intern/cycles/kernel/tables.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 */
+
+ccl_inline_constant float blackbody_table_r[][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}
+};
+
+ccl_inline_constant float blackbody_table_g[][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}
+};
+
+ccl_inline_constant float blackbody_table_b[][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}
+};
+
+ccl_inline_constant float cie_colour_match[][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}
+};
+
+/* clang-format on */
diff --git a/intern/cycles/kernel/textures.h b/intern/cycles/kernel/textures.h
new file mode 100644
index 00000000000..06074a1eca1
--- /dev/null
+++ b/intern/cycles/kernel/textures.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 KERNEL_TEX
+# define KERNEL_TEX(type, name)
+#endif
+
+/* BVH2, not used for OptiX or Embree. */
+KERNEL_TEX(float4, __bvh_nodes)
+KERNEL_TEX(float4, __bvh_leaf_nodes)
+KERNEL_TEX(uint, __prim_type)
+KERNEL_TEX(uint, __prim_visibility)
+KERNEL_TEX(uint, __prim_index)
+KERNEL_TEX(uint, __prim_object)
+KERNEL_TEX(uint, __object_node)
+KERNEL_TEX(float2, __prim_time)
+
+/* objects */
+KERNEL_TEX(KernelObject, __objects)
+KERNEL_TEX(Transform, __object_motion_pass)
+KERNEL_TEX(DecomposedTransform, __object_motion)
+KERNEL_TEX(uint, __object_flag)
+KERNEL_TEX(float, __object_volume_step)
+KERNEL_TEX(uint, __object_prim_offset)
+
+/* cameras */
+KERNEL_TEX(DecomposedTransform, __camera_motion)
+
+/* triangles */
+KERNEL_TEX(uint, __tri_shader)
+KERNEL_TEX(packed_float3, __tri_vnormal)
+KERNEL_TEX(uint4, __tri_vindex)
+KERNEL_TEX(uint, __tri_patch)
+KERNEL_TEX(float2, __tri_patch_uv)
+KERNEL_TEX(packed_float3, __tri_verts)
+
+/* curves */
+KERNEL_TEX(KernelCurve, __curves)
+KERNEL_TEX(float4, __curve_keys)
+KERNEL_TEX(KernelCurveSegment, __curve_segments)
+
+/* patches */
+KERNEL_TEX(uint, __patches)
+
+/* pointclouds */
+KERNEL_TEX(float4, __points)
+KERNEL_TEX(uint, __points_shader)
+
+/* attributes */
+KERNEL_TEX(uint4, __attributes_map)
+KERNEL_TEX(float, __attributes_float)
+KERNEL_TEX(float2, __attributes_float2)
+KERNEL_TEX(packed_float3, __attributes_float3)
+KERNEL_TEX(float4, __attributes_float4)
+KERNEL_TEX(uchar4, __attributes_uchar4)
+
+/* lights */
+KERNEL_TEX(KernelLightDistribution, __light_distribution)
+KERNEL_TEX(KernelLight, __lights)
+KERNEL_TEX(float2, __light_background_marginal_cdf)
+KERNEL_TEX(float2, __light_background_conditional_cdf)
+
+/* particles */
+KERNEL_TEX(KernelParticle, __particles)
+
+/* shaders */
+KERNEL_TEX(uint4, __svm_nodes)
+KERNEL_TEX(KernelShader, __shaders)
+
+/* lookup tables */
+KERNEL_TEX(float, __lookup_table)
+
+/* sobol */
+KERNEL_TEX(float, __sample_pattern_lut)
+
+/* image textures */
+KERNEL_TEX(TextureInfo, __texture_info)
+
+/* ies lights */
+KERNEL_TEX(float, __ies)
+
+#undef KERNEL_TEX
diff --git a/intern/cycles/kernel/types.h b/intern/cycles/kernel/types.h
new file mode 100644
index 00000000000..d4cb22d4af4
--- /dev/null
+++ b/intern/cycles/kernel/types.h
@@ -0,0 +1,1660 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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
+
+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 __POINTCLOUD__
+#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_GPU_RAYTRACING__
+# undef __BAKING__
+#endif /* __KERNEL_GPU_RAYTRACING__ */
+
+/* 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_POINTCLOUD)
+# undef __POINTCLOUD__
+# 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 : uint32_t {
+ /* --------------------------------------------------------------------
+ * 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_BACKFACING = (1U << 23U),
+ PATH_RAY_SUBSURFACE = (PATH_RAY_SUBSURFACE_RANDOM_WALK | PATH_RAY_SUBSURFACE_DISK |
+ PATH_RAY_SUBSURFACE_USE_FRESNEL | PATH_RAY_SUBSURFACE_BACKFACING),
+
+ /* Contribute to denoising features. */
+ PATH_RAY_DENOISING_FEATURES = (1U << 24U),
+
+ /* Render pass categories. */
+ PATH_RAY_SURFACE_PASS = (1U << 25U),
+ PATH_RAY_VOLUME_PASS = (1U << 26U),
+ PATH_RAY_ANY_PASS = (PATH_RAY_SURFACE_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_DENOISING_PREVIOUS,
+
+ /* 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;
+ float3 sum;
+} BsdfEval;
+
+/* Closure Filter */
+
+typedef enum FilterClosures {
+ FILTER_CLOSURE_EMISSION = (1 << 0),
+ FILTER_CLOSURE_DIFFUSE = (1 << 1),
+ FILTER_CLOSURE_GLOSSY = (1 << 2),
+ FILTER_CLOSURE_TRANSMISSION = (1 << 3),
+ FILTER_CLOSURE_TRANSPARENT = (1 << 4),
+ FILTER_CLOSURE_DIRECT_LIGHT = (1 << 5),
+} FilterClosures;
+
+/* 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_FISHEYE_LENS_POLYNOMIAL = 4,
+
+ PANORAMA_NUM_TYPES,
+};
+
+/* Direct Light Sampling */
+
+enum DirectLightSamplingType {
+ DIRECT_LIGHT_SAMPLING_MIS = 0,
+ DIRECT_LIGHT_SAMPLING_FORWARD = 1,
+ DIRECT_LIGHT_SAMPLING_NEE = 2,
+
+ DIRECT_LIGHT_SAMPLING_NUM,
+};
+
+/* Differential */
+
+typedef struct differential3 {
+ float3 dx;
+ float3 dy;
+} differential3;
+
+typedef struct differential {
+ float dx;
+ float dy;
+} differential;
+
+/* Ray */
+
+typedef struct RaySelfPrimitives {
+ int prim; /* Primitive the ray is starting from */
+ int object; /* Instance prim is a part of */
+ int light_prim; /* Light primitive */
+ int light_object; /* Light object */
+} RaySelfPrimitives;
+
+typedef struct Ray {
+ float3 P; /* origin */
+ float3 D; /* direction */
+ float t; /* length of the ray */
+ float time; /* time (for motion blur) */
+
+ RaySelfPrimitives self;
+
+#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_CURVE_THICK = (1 << 1),
+ PRIMITIVE_CURVE_RIBBON = (1 << 2),
+ PRIMITIVE_POINT = (1 << 3),
+ PRIMITIVE_VOLUME = (1 << 4),
+ PRIMITIVE_LAMP = (1 << 5),
+
+ PRIMITIVE_MOTION = (1 << 6),
+ PRIMITIVE_MOTION_TRIANGLE = (PRIMITIVE_TRIANGLE | PRIMITIVE_MOTION),
+ PRIMITIVE_MOTION_CURVE_THICK = (PRIMITIVE_CURVE_THICK | PRIMITIVE_MOTION),
+ PRIMITIVE_MOTION_CURVE_RIBBON = (PRIMITIVE_CURVE_RIBBON | PRIMITIVE_MOTION),
+ PRIMITIVE_MOTION_POINT = (PRIMITIVE_POINT | PRIMITIVE_MOTION),
+
+ PRIMITIVE_CURVE = (PRIMITIVE_CURVE_THICK | PRIMITIVE_CURVE_RIBBON),
+
+ PRIMITIVE_ALL = (PRIMITIVE_TRIANGLE | PRIMITIVE_CURVE | PRIMITIVE_POINT | PRIMITIVE_VOLUME |
+ PRIMITIVE_LAMP | PRIMITIVE_MOTION),
+
+ PRIMITIVE_NUM_SHAPES = 6,
+ PRIMITIVE_NUM_BITS = PRIMITIVE_NUM_SHAPES + 1, /* All shapes + motion bit. */
+ PRIMITIVE_NUM = PRIMITIVE_NUM_SHAPES * 2, /* With and without motion. */
+} PrimitiveType;
+
+/* Convert type to index in range 0..PRIMITIVE_NUM-1. */
+#define PRIMITIVE_INDEX(type) (bitscan((uint32_t)(type)) * 2 + (((type)&PRIMITIVE_MOTION) ? 1 : 0))
+
+/* Pack segment into type value to save space. */
+#define PRIMITIVE_PACK_SEGMENT(type, segment) ((segment << PRIMITIVE_NUM_BITS) | (type))
+#define PRIMITIVE_UNPACK_SEGMENT(type) (type >> PRIMITIVE_NUM_BITS)
+
+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_POINT_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;
+ float fisheye_lens_polynomial_bias;
+ float4 fisheye_lens_polynomial_coefficients;
+
+ /* 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;
+
+ /* Closure filter. */
+ int filter_closures;
+
+ /* MIS debugging. */
+ int direct_light_sampling_type;
+
+ /* 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),
+ BVH_LAYOUT_METAL = (1 << 5),
+ BVH_LAYOUT_MULTI_METAL = (1 << 6),
+ BVH_LAYOUT_MULTI_METAL_EMBREE = (1 << 7),
+
+ /* 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 | BVH_LAYOUT_METAL,
+} 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;
+#elif defined __METALRT__
+ metalrt_as_type 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;
+ uint sample_offset;
+
+ 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 : uint32_t {
+ /* Shader nodes. */
+ KERNEL_FEATURE_NODE_BSDF = (1U << 0U),
+ KERNEL_FEATURE_NODE_EMISSION = (1U << 1U),
+ KERNEL_FEATURE_NODE_VOLUME = (1U << 2U),
+ KERNEL_FEATURE_NODE_BUMP = (1U << 3U),
+ KERNEL_FEATURE_NODE_BUMP_STATE = (1U << 4U),
+ KERNEL_FEATURE_NODE_VORONOI_EXTRA = (1U << 5U),
+ KERNEL_FEATURE_NODE_RAYTRACE = (1U << 6U),
+ KERNEL_FEATURE_NODE_AOV = (1U << 7U),
+ KERNEL_FEATURE_NODE_LIGHT_PATH = (1U << 8U),
+
+ /* Use denoising kernels and output denoising passes. */
+ KERNEL_FEATURE_DENOISING = (1U << 9U),
+
+ /* Use path tracing kernels. */
+ KERNEL_FEATURE_PATH_TRACING = (1U << 10U),
+
+ /* BVH/sampling kernel features. */
+ KERNEL_FEATURE_POINTCLOUD = (1U << 11U),
+ 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_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/util/differential.h b/intern/cycles/kernel/util/differential.h
new file mode 100644
index 00000000000..17187083019
--- /dev/null
+++ b/intern/cycles/kernel/util/differential.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.
+ */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+/* See "Tracing Ray Differentials", Homan Igehy, 1999. */
+
+ccl_device void differential_transfer(ccl_private differential3 *surface_dP,
+ const differential3 ray_dP,
+ float3 ray_D,
+ const differential3 ray_dD,
+ float3 surface_Ng,
+ float ray_t)
+{
+ /* ray differential transfer through homogeneous medium, to
+ * compute dPdx/dy at a shading point from the incoming ray */
+
+ float3 tmp = ray_D / dot(ray_D, surface_Ng);
+ float3 tmpx = ray_dP.dx + ray_t * ray_dD.dx;
+ float3 tmpy = ray_dP.dy + ray_t * ray_dD.dy;
+
+ surface_dP->dx = tmpx - dot(tmpx, surface_Ng) * tmp;
+ surface_dP->dy = tmpy - dot(tmpy, surface_Ng) * tmp;
+}
+
+ccl_device void differential_incoming(ccl_private differential3 *dI, const differential3 dD)
+{
+ /* compute dIdx/dy at a shading point, we just need to negate the
+ * differential of the ray direction */
+
+ dI->dx = -dD.dx;
+ dI->dy = -dD.dy;
+}
+
+ccl_device void differential_dudv(ccl_private differential *du,
+ ccl_private differential *dv,
+ float3 dPdu,
+ float3 dPdv,
+ differential3 dP,
+ float3 Ng)
+{
+ /* now we have dPdx/dy from the ray differential transfer, and dPdu/dv
+ * from the primitive, we can compute dudx/dy and dvdx/dy. these are
+ * mainly used for differentials of arbitrary mesh attributes. */
+
+ /* find most stable axis to project to 2D */
+ float xn = fabsf(Ng.x);
+ float yn = fabsf(Ng.y);
+ float zn = fabsf(Ng.z);
+
+ if (zn < xn || zn < yn) {
+ if (yn < xn || yn < zn) {
+ dPdu.x = dPdu.y;
+ dPdv.x = dPdv.y;
+ dP.dx.x = dP.dx.y;
+ dP.dy.x = dP.dy.y;
+ }
+
+ dPdu.y = dPdu.z;
+ dPdv.y = dPdv.z;
+ dP.dx.y = dP.dx.z;
+ dP.dy.y = dP.dy.z;
+ }
+
+ /* using Cramer's rule, we solve for dudx and dvdx in a 2x2 linear system,
+ * and the same for dudy and dvdy. the denominator is the same for both
+ * solutions, so we compute it only once.
+ *
+ * dP.dx = dPdu * dudx + dPdv * dvdx;
+ * dP.dy = dPdu * dudy + dPdv * dvdy; */
+
+ float det = (dPdu.x * dPdv.y - dPdv.x * dPdu.y);
+
+ if (det != 0.0f)
+ det = 1.0f / det;
+
+ du->dx = (dP.dx.x * dPdv.y - dP.dx.y * dPdv.x) * det;
+ dv->dx = (dP.dx.y * dPdu.x - dP.dx.x * dPdu.y) * det;
+
+ du->dy = (dP.dy.x * dPdv.y - dP.dy.y * dPdv.x) * det;
+ dv->dy = (dP.dy.y * dPdu.x - dP.dy.x * dPdu.y) * det;
+}
+
+ccl_device differential differential_zero()
+{
+ differential d;
+ d.dx = 0.0f;
+ d.dy = 0.0f;
+
+ return d;
+}
+
+ccl_device differential3 differential3_zero()
+{
+ differential3 d;
+ d.dx = zero_float3();
+ d.dy = zero_float3();
+
+ return d;
+}
+
+/* Compact ray differentials that are just a scale to reduce memory usage and
+ * access cost in GPU.
+ *
+ * See above for more accurate reference implementations.
+ *
+ * TODO: also store the more compact version in ShaderData and recompute where
+ * needed? */
+
+ccl_device_forceinline float differential_zero_compact()
+{
+ return 0.0f;
+}
+
+ccl_device_forceinline float differential_make_compact(const differential3 D)
+{
+ return 0.5f * (len(D.dx) + len(D.dy));
+}
+
+ccl_device_forceinline void differential_transfer_compact(ccl_private differential3 *surface_dP,
+ const float ray_dP,
+ const float3 /* ray_D */,
+ const float ray_dD,
+ const float3 surface_Ng,
+ const float ray_t)
+{
+ /* ray differential transfer through homogeneous medium, to
+ * compute dPdx/dy at a shading point from the incoming ray */
+ float scale = ray_dP + ray_t * ray_dD;
+
+ float3 dx, dy;
+ make_orthonormals(surface_Ng, &dx, &dy);
+ surface_dP->dx = dx * scale;
+ surface_dP->dy = dy * scale;
+}
+
+ccl_device_forceinline void differential_incoming_compact(ccl_private differential3 *dI,
+ const float3 D,
+ const float dD)
+{
+ /* compute dIdx/dy at a shading point, we just need to negate the
+ * differential of the ray direction */
+
+ float3 dx, dy;
+ make_orthonormals(D, &dx, &dy);
+
+ dI->dx = dD * dx;
+ dI->dy = dD * dy;
+}
+
+CCL_NAMESPACE_END
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 6edb5261b32..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
- gpu_display.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
- film.h
- geometry.h
- gpu_display.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 aaf21ad9fd2..00000000000
--- a/intern/cycles/render/attribute.cpp
+++ /dev/null
@@ -1,891 +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_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;
- 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 3682b55049a..00000000000
--- a/intern/cycles/render/buffers.cpp
+++ /dev/null
@@ -1,361 +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(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 && full_x == other.full_x &&
- full_y == other.full_y && full_width == other.full_width &&
- full_height == other.full_height && offset == other.offset && stride == other.stride &&
- pass_stride == other.pass_stride && layer == other.layer && view == other.view &&
- 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 184ac7197af..00000000000
--- a/intern/cycles/render/buffers.h
+++ /dev/null
@@ -1,190 +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;
-
- /* 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/denoising.h b/intern/cycles/render/denoising.h
deleted file mode 100644
index 097cc570d06..00000000000
--- a/intern/cycles/render/denoising.h
+++ /dev/null
@@ -1,216 +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 __DENOISING_H__
-#define __DENOISING_H__
-
-#if 0
-
-/* TODO(sergey): Make it explicit and clear when something is a denoiser, its pipeline or
- * parameters. Currently it is an annoying mixture of terms used interchangeably. */
-
-# include "device/device.h"
-
-# include "render/buffers.h"
-
-# include "util/util_string.h"
-# include "util/util_unique_ptr.h"
-# include "util/util_vector.h"
-
-# include <OpenImageIO/imageio.h>
-
-OIIO_NAMESPACE_USING
-
-CCL_NAMESPACE_BEGIN
-
-/* Denoiser pipeline */
-
-class DenoiserPipeline {
- public:
- DenoiserPipeline(DeviceInfo &device_info);
- ~DenoiserPipeline();
-
- bool run();
-
- /* Error message after running, in case of failure. */
- string error;
-
- /* Sequential list of frame filepaths to denoise. */
- vector<string> input;
- /* Sequential list of frame filepaths to write result to. Empty entries
- * are skipped, so only a subset of the sequence can be denoised while
- * taking into account all input frames. */
- vector<string> output;
-
- /* Sample number override, takes precedence over values from input frames. */
- int samples_override;
- /* Tile size for processing on device. */
- int2 tile_size;
-
- /* Equivalent to the settings in the regular denoiser. */
- DenoiseParams params;
-
- protected:
- friend class DenoiseTask;
-
- Stats stats;
- Profiler profiler;
- Device *device;
-
- int num_frames;
-};
-
-/* Denoise Image Layer */
-
-struct DenoiseImageLayer {
- string name;
- /* All channels belonging to this DenoiseImageLayer. */
- vector<string> channels;
- /* Layer to image channel mapping. */
- vector<int> layer_to_image_channel;
-
- /* Sample amount that was used for rendering this layer. */
- int samples;
-
- /* Device input channel will be copied from image channel input_to_image_channel[i]. */
- vector<int> input_to_image_channel;
-
- /* input_to_image_channel of the secondary frames, if any are used. */
- vector<vector<int>> neighbor_input_to_image_channel;
-
- /* Write i-th channel of the processing output to output_to_image_channel[i]-th channel of the
- * file. */
- vector<int> output_to_image_channel;
-
- /* Detect whether this layer contains a full set of channels and set up the offsets accordingly.
- */
- bool detect_denoising_channels();
-
- /* Map the channels of a secondary frame to the channels that are required for processing,
- * fill neighbor_input_to_image_channel if all are present or return false if a channel are
- * missing. */
- bool match_channels(int neighbor,
- const std::vector<string> &channelnames,
- const std::vector<string> &neighbor_channelnames);
-};
-
-/* Denoise Image Data */
-
-class DenoiseImage {
- public:
- DenoiseImage();
- ~DenoiseImage();
-
- /* Dimensions */
- int width, height, num_channels;
-
- /* Samples */
- int samples;
-
- /* Pixel buffer with interleaved channels. */
- array<float> pixels;
-
- /* Image file handles */
- ImageSpec in_spec;
- vector<unique_ptr<ImageInput>> in_neighbors;
-
- /* Render layers */
- vector<DenoiseImageLayer> layers;
-
- void free();
-
- /* Open the input image, parse its channels, open the output image and allocate the output
- * buffer. */
- bool load(const string &in_filepath, string &error);
-
- /* Load neighboring frames. */
- bool load_neighbors(const vector<string> &filepaths, const vector<int> &frames, string &error);
-
- /* Load subset of pixels from file buffer into input buffer, as needed for denoising
- * on the device. Channels are reshuffled following the provided mapping. */
- void read_pixels(const DenoiseImageLayer &layer, float *input_pixels);
- bool read_neighbor_pixels(int neighbor, const DenoiseImageLayer &layer, float *input_pixels);
-
- bool save_output(const string &out_filepath, string &error);
-
- protected:
- /* Parse input file channels, separate them into DenoiseImageLayers,
- * detect DenoiseImageLayers with full channel sets,
- * fill layers and set up the output channels and passthrough map. */
- bool parse_channels(const ImageSpec &in_spec, string &error);
-
- void close_input();
-};
-
-/* Denoise Task */
-
-class DenoiseTask {
- public:
- DenoiseTask(Device *device,
- DenoiserPipeline *denoiser,
- int frame,
- const vector<int> &neighbor_frames);
- ~DenoiseTask();
-
- /* Task stages */
- bool load();
- bool exec();
- bool save();
- void free();
-
- string error;
-
- protected:
- /* Denoiser parameters and device */
- DenoiserPipeline *denoiser;
- Device *device;
-
- /* Frame number to be denoised */
- int frame;
- vector<int> neighbor_frames;
-
- /* Image file data */
- DenoiseImage image;
- int current_layer;
-
- /* Device input buffer */
- device_vector<float> input_pixels;
-
- /* Tiles */
- thread_mutex tiles_mutex;
- list<RenderTile> tiles;
- int num_tiles;
-
- thread_mutex output_mutex;
- map<int, device_vector<float> *> output_pixels;
-
- /* Task handling */
- bool load_input_pixels(int layer);
- void create_task(DeviceTask &task);
-
- /* Device task callbacks */
- bool acquire_tile(Device *device, Device *tile_device, RenderTile &tile);
- void map_neighboring_tiles(RenderTileNeighbors &neighbors, Device *tile_device);
- void unmap_neighboring_tiles(RenderTileNeighbors &neighbors);
- void release_tile();
- bool get_cancel();
-};
-
-CCL_NAMESPACE_END
-
-#endif
-
-#endif /* __DENOISING_H__ */
diff --git a/intern/cycles/render/film.cpp b/intern/cycles/render/film.cpp
deleted file mode 100644
index ad3336ca089..00000000000
--- a/intern/cycles/render/film.cpp
+++ /dev/null
@@ -1,691 +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_RENDER_TIME:
- 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;
- }
- }
-
- if (pass_type == PASS_AO) {
- kernel_features |= KERNEL_FEATURE_NODE_RAYTRACE;
- }
- }
-
- 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 4de458de271..00000000000
--- a/intern/cycles/render/geometry.cpp
+++ /dev/null
@@ -1,2181 +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 */
-
-PackFlags operator|=(PackFlags &pack_flags, uint32_t value)
-{
- pack_flags = (PackFlags)((uint32_t)pack_flags | value);
- return pack_flags;
-}
-
-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;
- optix_prim_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->curvekey_offset;
- else if (element == ATTR_ELEMENT_CURVE_KEY_MOTION)
- offset -= hair->curvekey_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);
- }
- }
-
- /* 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_key_size = 0;
- size_t curve_size = 0;
-
- size_t patch_size = 0;
- size_t face_size = 0;
- size_t corner_size = 0;
-
- size_t optix_prim_size = 0;
-
- foreach (Geometry *geom, scene->geometry) {
- if (geom->optix_prim_offset != optix_prim_size) {
- /* 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;
- }
-
- if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
- Mesh *mesh = static_cast<Mesh *>(geom);
-
- 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();
-
- mesh->optix_prim_offset = optix_prim_size;
- optix_prim_size += mesh->num_triangles();
- }
- else if (geom->is_hair()) {
- Hair *hair = static_cast<Hair *>(geom);
-
- hair->curvekey_offset = curve_key_size;
- hair->prim_offset = curve_size;
-
- curve_key_size += hair->get_curve_keys().size();
- curve_size += hair->num_curves();
-
- hair->optix_prim_offset = optix_prim_size;
- optix_prim_size += hair->num_segments();
- }
- }
-}
-
-void GeometryManager::device_update_mesh(
- Device *, DeviceScene *dscene, Scene *scene, bool for_displacement, 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 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();
- }
- }
-
- /* Create mapping from triangle to primitive triangle array. */
- vector<uint> tri_prim_index(tri_size);
- if (for_displacement) {
- /* For displacement kernels we do some trickery to make them believe
- * we've got all required data ready. However, that data is different
- * from final render kernels since we don't have BVH yet, so can't
- * really use same semantic of arrays.
- */
- foreach (Geometry *geom, scene->geometry) {
- if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
- Mesh *mesh = static_cast<Mesh *>(geom);
- for (size_t i = 0; i < mesh->num_triangles(); ++i) {
- tri_prim_index[i + mesh->prim_offset] = 3 * (i + mesh->prim_offset);
- }
- }
- }
- }
- else {
- for (size_t i = 0; i < dscene->prim_index.size(); ++i) {
- if ((dscene->prim_type[i] & PRIMITIVE_ALL_TRIANGLE) != 0) {
- tri_prim_index[dscene->prim_index[i]] = dscene->prim_tri_index[i];
- }
- }
- }
-
- /* Fill in all the arrays. */
- if (tri_size != 0) {
- /* normals */
- progress.set_status("Updating Mesh", "Computing normals");
-
- 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->triangles_is_modified() || mesh->vert_patch_uv_is_modified() || copy_all_data) {
- mesh->pack_verts(tri_prim_index,
- &tri_vindex[mesh->prim_offset],
- &tri_patch[mesh->prim_offset],
- &tri_patch_uv[mesh->vert_offset],
- mesh->vert_offset,
- mesh->prim_offset);
- }
-
- if (progress.get_cancel())
- return;
- }
- }
-
- /* vertex coordinates */
- progress.set_status("Updating Mesh", "Copying Mesh to device");
-
- 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_size != 0) {
- progress.set_status("Updating Mesh", "Copying Strands to device");
-
- float4 *curve_keys = dscene->curve_keys.alloc(curve_key_size);
- float4 *curves = dscene->curves.alloc(curve_size);
-
- const bool copy_all_data = dscene->curve_keys.need_realloc() || dscene->curves.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->curvekey_offset],
- &curves[hair->prim_offset],
- hair->curvekey_offset);
- if (progress.get_cancel())
- return;
- }
- }
-
- dscene->curve_keys.copy_to_device_if_modified();
- dscene->curves.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],
- mesh->vert_offset,
- mesh->face_offset,
- mesh->corner_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();
- }
-
- if (for_displacement) {
- float4 *prim_tri_verts = dscene->prim_tri_verts.alloc(tri_size * 3);
- foreach (Geometry *geom, scene->geometry) {
- if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
- Mesh *mesh = static_cast<Mesh *>(geom);
- for (size_t i = 0; i < mesh->num_triangles(); ++i) {
- Mesh::Triangle t = mesh->get_triangle(i);
- size_t offset = 3 * (i + mesh->prim_offset);
- prim_tri_verts[offset + 0] = float3_to_float4(mesh->verts[t.v[0]]);
- prim_tri_verts[offset + 1] = float3_to_float4(mesh->verts[t.v[1]]);
- prim_tri_verts[offset + 2] = float3_to_float4(mesh->verts[t.v[2]]);
- }
- }
- }
- dscene->prim_tri_verts.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);
-
- PackFlags pack_flags = PackFlags::PACK_NONE;
-
- if (scene->bvh == nullptr) {
- pack_flags |= PackFlags::PACK_ALL;
- }
-
- if (dscene->prim_visibility.is_modified()) {
- pack_flags |= PackFlags::PACK_VISIBILITY;
- }
-
- 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 {
- progress.set_status("Updating Scene BVH", "Packing BVH primitives");
-
- size_t num_prims = 0;
- size_t num_tri_verts = 0;
- foreach (Geometry *geom, scene->geometry) {
- if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
- Mesh *mesh = static_cast<Mesh *>(geom);
- num_prims += mesh->num_triangles();
- num_tri_verts += 3 * mesh->num_triangles();
- }
- else if (geom->is_hair()) {
- Hair *hair = static_cast<Hair *>(geom);
- num_prims += hair->num_segments();
- }
- }
-
- pack.root_index = -1;
-
- if (pack_flags != PackFlags::PACK_ALL) {
- /* if we do not need to recreate the BVH, then only the vertices are updated, so we can
- * safely retake the memory */
- dscene->prim_tri_verts.give_data(pack.prim_tri_verts);
-
- if ((pack_flags & PackFlags::PACK_VISIBILITY) != 0) {
- dscene->prim_visibility.give_data(pack.prim_visibility);
- }
- }
- else {
- /* It is not strictly necessary to skip those resizes we if do not have to repack, as the OS
- * will not allocate pages if we do not touch them, however it does help catching bugs. */
- pack.prim_tri_index.resize(num_prims);
- pack.prim_tri_verts.resize(num_tri_verts);
- pack.prim_type.resize(num_prims);
- pack.prim_index.resize(num_prims);
- pack.prim_object.resize(num_prims);
- pack.prim_visibility.resize(num_prims);
- }
-
- // Merge visibility flags of all objects and find object index for non-instanced geometry
- unordered_map<const Geometry *, pair<int, uint>> geometry_to_object_info;
- geometry_to_object_info.reserve(scene->geometry.size());
- foreach (Object *ob, scene->objects) {
- const Geometry *const geom = ob->get_geometry();
- pair<int, uint> &info = geometry_to_object_info[geom];
- info.second |= ob->visibility_for_tracing();
- if (!geom->is_instanced()) {
- info.first = ob->get_device_index();
- }
- }
-
- TaskPool pool;
- // Iterate over scene mesh list instead of objects, since 'optix_prim_offset' was calculated
- // based on that list, which may be ordered differently from the object list.
- foreach (Geometry *geom, scene->geometry) {
- /* Make a copy of the pack_flags so the current geometry's flags do not pollute the others'.
- */
- PackFlags geom_pack_flags = pack_flags;
-
- if (geom->is_modified()) {
- geom_pack_flags |= PackFlags::PACK_VERTICES;
- }
-
- if (geom_pack_flags == PACK_NONE) {
- continue;
- }
-
- const pair<int, uint> &info = geometry_to_object_info[geom];
- pool.push(function_bind(
- &Geometry::pack_primitives, geom, &pack, info.first, info.second, geom_pack_flags));
- }
- pool.wait_work();
- }
-
- /* 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_tri_index.size() && (dscene->prim_tri_index.need_realloc() || has_bvh2_layout)) {
- dscene->prim_tri_index.steal_data(pack.prim_tri_index);
- dscene->prim_tri_index.copy_to_device();
- }
- if (pack.prim_tri_verts.size()) {
- dscene->prim_tri_verts.steal_data(pack.prim_tri_verts);
- dscene->prim_tri_verts.copy_to_device();
- }
- if (pack.prim_type.size() && (dscene->prim_type.need_realloc() || has_bvh2_layout)) {
- dscene->prim_type.steal_data(pack.prim_type);
- dscene->prim_type.copy_to_device();
- }
- if (pack.prim_visibility.size() && (dscene->prim_visibility.is_modified() || has_bvh2_layout)) {
- dscene->prim_visibility.steal_data(pack.prim_visibility);
- dscene->prim_visibility.copy_to_device();
- }
- if (pack.prim_index.size() && (dscene->prim_index.need_realloc() || has_bvh2_layout)) {
- dscene->prim_index.steal_data(pack.prim_index);
- dscene->prim_index.copy_to_device();
- }
- if (pack.prim_object.size() && (dscene->prim_object.need_realloc() || has_bvh2_layout)) {
- dscene->prim_object.steal_data(pack.prim_object);
- dscene->prim_object.copy_to_device();
- }
- if (pack.prim_time.size() && (dscene->prim_time.need_realloc() || has_bvh2_layout)) {
- 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_tri_verts.tag_realloc();
- dscene->prim_tri_index.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_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();
- }
- }
-
- 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_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();
- }
-
- 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;
- 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() &&
- (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;
- }
-
- 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) {
- 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) {
- 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, true, 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. */
- bool displacement_done = false;
- size_t num_bvh = 0;
-
- {
- 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, dscene, scene, mesh, progress)) {
- displacement_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) {
- 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, false, 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_tri_verts.clear_modified();
- dscene->prim_tri_index.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_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->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_tri_verts.free_if_need_realloc(force_free);
- dscene->prim_tri_index.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_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->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 7db122f69cb..00000000000
--- a/intern/cycles/render/geometry.h
+++ /dev/null
@@ -1,298 +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;
-
-/* Flags used to determine which geometry data need to be packed. */
-enum PackFlags : uint32_t {
- PACK_NONE = 0u,
-
- /* Pack the geometry information (e.g. triangle or curve keys indices). */
- PACK_GEOMETRY = (1u << 0),
-
- /* Pack the vertices, for Meshes and Volumes' bounding meshes. */
- PACK_VERTICES = (1u << 1),
-
- /* Pack the visibility flags for each triangle or curve. */
- PACK_VISIBILITY = (1u << 2),
-
- PACK_ALL = (PACK_GEOMETRY | PACK_VERTICES | PACK_VISIBILITY),
-};
-
-PackFlags operator|=(PackFlags &pack_flags, uint32_t value);
-
-/* 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;
- size_t optix_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 void pack_primitives(PackedBVH *pack,
- int object,
- uint visibility,
- PackFlags pack_flags) = 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, DeviceScene *dscene, 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,
- bool for_displacement,
- 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/gpu_display.cpp b/intern/cycles/render/gpu_display.cpp
deleted file mode 100644
index a8f0cc50583..00000000000
--- a/intern/cycles/render/gpu_display.cpp
+++ /dev/null
@@ -1,227 +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/gpu_display.h"
-
-#include "render/buffers.h"
-#include "util/util_logging.h"
-
-CCL_NAMESPACE_BEGIN
-
-void GPUDisplay::reset(const BufferParams &buffer_params)
-{
- thread_scoped_lock lock(mutex_);
-
- const GPUDisplayParams old_params = params_;
-
- params_.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 GPUDisplay::mark_texture_updated()
-{
- texture_state_.is_outdated = false;
- texture_state_.is_usable = true;
-}
-
-/* --------------------------------------------------------------------
- * Update procedure.
- */
-
-bool GPUDisplay::update_begin(int texture_width, int texture_height)
-{
- DCHECK(!update_state_.is_active);
-
- if (update_state_.is_active) {
- LOG(ERROR) << "Attempt to re-activate update process.";
- return false;
- }
-
- /* Get parameters within a mutex lock, to avoid reset() modifying them at the same time.
- * The update itself is non-blocking however, for better performance and to avoid
- * potential deadlocks due to locks held by the subclass. */
- GPUDisplayParams params;
- {
- thread_scoped_lock lock(mutex_);
- params = params_;
- texture_state_.size = make_int2(texture_width, texture_height);
- }
-
- if (!do_update_begin(params, texture_width, texture_height)) {
- LOG(ERROR) << "GPUDisplay implementation could not begin update.";
- return false;
- }
-
- update_state_.is_active = true;
-
- return true;
-}
-
-void GPUDisplay::update_end()
-{
- DCHECK(update_state_.is_active);
-
- if (!update_state_.is_active) {
- LOG(ERROR) << "Attempt to deactivate inactive update process.";
- return;
- }
-
- do_update_end();
-
- update_state_.is_active = false;
-}
-
-int2 GPUDisplay::get_texture_size() const
-{
- return texture_state_.size;
-}
-
-/* --------------------------------------------------------------------
- * Texture update from CPU buffer.
- */
-
-void GPUDisplay::copy_pixels_to_texture(
- const half4 *rgba_pixels, int texture_x, int texture_y, int pixels_width, int pixels_height)
-{
- DCHECK(update_state_.is_active);
-
- if (!update_state_.is_active) {
- LOG(ERROR) << "Attempt to copy pixels data outside of GPUDisplay update.";
- return;
- }
-
- mark_texture_updated();
- do_copy_pixels_to_texture(rgba_pixels, texture_x, texture_y, pixels_width, pixels_height);
-}
-
-/* --------------------------------------------------------------------
- * Texture buffer mapping.
- */
-
-half4 *GPUDisplay::map_texture_buffer()
-{
- DCHECK(!texture_buffer_state_.is_mapped);
- DCHECK(update_state_.is_active);
-
- if (texture_buffer_state_.is_mapped) {
- LOG(ERROR) << "Attempt to re-map an already mapped texture buffer.";
- return nullptr;
- }
-
- if (!update_state_.is_active) {
- LOG(ERROR) << "Attempt to copy pixels data outside of GPUDisplay update.";
- return nullptr;
- }
-
- half4 *mapped_rgba_pixels = do_map_texture_buffer();
-
- if (mapped_rgba_pixels) {
- texture_buffer_state_.is_mapped = true;
- }
-
- return mapped_rgba_pixels;
-}
-
-void GPUDisplay::unmap_texture_buffer()
-{
- DCHECK(texture_buffer_state_.is_mapped);
-
- if (!texture_buffer_state_.is_mapped) {
- LOG(ERROR) << "Attempt to unmap non-mapped texture buffer.";
- return;
- }
-
- texture_buffer_state_.is_mapped = false;
-
- mark_texture_updated();
- do_unmap_texture_buffer();
-}
-
-/* --------------------------------------------------------------------
- * Graphics interoperability.
- */
-
-DeviceGraphicsInteropDestination GPUDisplay::graphics_interop_get()
-{
- DCHECK(!texture_buffer_state_.is_mapped);
- DCHECK(update_state_.is_active);
-
- if (texture_buffer_state_.is_mapped) {
- LOG(ERROR)
- << "Attempt to use graphics interoperability mode while the texture buffer is mapped.";
- return DeviceGraphicsInteropDestination();
- }
-
- if (!update_state_.is_active) {
- LOG(ERROR) << "Attempt to use graphics interoperability outside of GPUDisplay update.";
- return DeviceGraphicsInteropDestination();
- }
-
- /* Assume that interop will write new values to the texture. */
- mark_texture_updated();
-
- return do_graphics_interop_get();
-}
-
-void GPUDisplay::graphics_interop_activate()
-{
-}
-
-void GPUDisplay::graphics_interop_deactivate()
-{
-}
-
-/* --------------------------------------------------------------------
- * Drawing.
- */
-
-bool GPUDisplay::draw()
-{
- /* Get parameters within a mutex lock, to avoid reset() modifying them at the same time.
- * The drawing itself is non-blocking however, for better performance and to avoid
- * potential deadlocks due to locks held by the subclass. */
- GPUDisplayParams 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) {
- do_draw(params);
- }
-
- return !is_outdated;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/gpu_display.h b/intern/cycles/render/gpu_display.h
deleted file mode 100644
index 3c3cfaea513..00000000000
--- a/intern/cycles/render/gpu_display.h
+++ /dev/null
@@ -1,247 +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 "device/device_graphics_interop.h"
-#include "util/util_half.h"
-#include "util/util_thread.h"
-#include "util/util_types.h"
-
-CCL_NAMESPACE_BEGIN
-
-class BufferParams;
-
-/* GPUDisplay class takes care of drawing render result in a viewport. The render result is stored
- * in a GPU-side texture, which is updated from a path tracer and drawn by an application.
- *
- * The base GPUDisplay does some special texture state tracking, which allows render Session to
- * make decisions on whether reset for an updated state is possible or not. This state should only
- * be tracked in a base class and a particular implementation should not worry about it.
- *
- * The subclasses should only implement the pure virtual methods, which allows them to not worry
- * about parent method calls, which helps them to be as small and reliable as possible. */
-
-class GPUDisplayParams {
- public:
- /* Offset of the display within a viewport.
- * For example, set to a lower-bottom corner of border render in Blender's viewport. */
- int2 offset = make_int2(0, 0);
-
- /* Full viewport size.
- *
- * NOTE: Is not affected by the resolution divider. */
- int2 full_size = make_int2(0, 0);
-
- /* Effective viewport size.
- * In the case of border render, size of the border rectangle.
- *
- * NOTE: Is not affected by the resolution divider. */
- int2 size = make_int2(0, 0);
-
- bool modified(const GPUDisplayParams &other) const
- {
- return !(offset == other.offset && full_size == other.full_size && size == other.size);
- }
-};
-
-class GPUDisplay {
- public:
- GPUDisplay() = default;
- virtual ~GPUDisplay() = default;
-
- /* Reset the display for the new state of render session. Is called whenever session is reset,
- * which happens on changes like viewport navigation or viewport dimension change.
- *
- * This call will configure parameters for a changed buffer and reset the texture state. */
- void reset(const BufferParams &buffer_params);
-
- const GPUDisplayParams &get_params() const
- {
- return params_;
- }
-
- /* --------------------------------------------------------------------
- * Update procedure.
- *
- * These calls indicates a desire of the caller to update content of the displayed texture. */
-
- /* Returns true when update is ready. Update should be finished with update_end().
- *
- * If false is returned then no update is possible, and no update_end() call is needed.
- *
- * The texture width and height denotes an actual resolution of the underlying render result. */
- bool update_begin(int texture_width, int texture_height);
-
- void update_end();
-
- /* Get currently configured texture size of the display (as configured by `update_begin()`. */
- int2 get_texture_size() const;
-
- /* --------------------------------------------------------------------
- * Texture update from CPU buffer.
- *
- * NOTE: The GPUDisplay should be marked for an update being in process with `update_begin()`.
- *
- * Most portable implementation, which must be supported by all platforms. Might not be the most
- * efficient one.
- */
-
- /* Copy buffer of rendered pixels of a given size into a given position of the texture.
- *
- * This function does not acquire a lock. The reason for this is is to allow use of this function
- * for partial updates from different devices. In this case the caller will acquire the lock
- * once, update all the slices and release
- * the lock once. This will ensure that draw() will never use partially updated texture. */
- void copy_pixels_to_texture(
- const half4 *rgba_pixels, int texture_x, int texture_y, int pixels_width, int pixels_height);
-
- /* --------------------------------------------------------------------
- * Texture buffer mapping.
- *
- * This functionality is used to update GPU-side texture content without need to maintain CPU
- * side buffer on the caller.
- *
- * NOTE: The GPUDisplay should be marked for an update being in process with `update_begin()`.
- *
- * NOTE: Texture buffer can not be mapped while graphics interoperability is active. This means
- * that `map_texture_buffer()` is not allowed between `graphics_interop_begin()` and
- * `graphics_interop_end()` calls.
- */
-
- /* Map pixels memory form texture to a buffer available for write from CPU. Width and height will
- * define a requested size of the texture to write to.
- * Upon success a non-null pointer is returned and the texture buffer is to be unmapped.
- * If an error happens during mapping, or if mapping is not supported by this GPU display a
- * null pointer is returned and the buffer is NOT to be unmapped.
- *
- * NOTE: Usually the implementation will rely on a GPU context of some sort, and the GPU context
- * is often can not be bound to two threads simultaneously, and can not be released from a
- * different thread. This means that the mapping API should be used from the single thread only,
- */
- half4 *map_texture_buffer();
- void unmap_texture_buffer();
-
- /* --------------------------------------------------------------------
- * Graphics interoperability.
- *
- * A special code path which allows to update texture content directly from the GPU compute
- * device. Complementary part of DeviceGraphicsInterop.
- *
- * NOTE: Graphics interoperability can not be used while the texture buffer is mapped. This means
- * that `graphics_interop_get()` is not allowed between `map_texture_buffer()` and
- * `unmap_texture_buffer()` calls. */
-
- /* Get GPUDisplay graphics interoperability information which acts as a destination for the
- * device API. */
- DeviceGraphicsInteropDestination graphics_interop_get();
-
- /* (De)activate GPU display for graphics interoperability outside of regular display update
- * routines. */
- virtual void graphics_interop_activate();
- virtual void graphics_interop_deactivate();
-
- /* --------------------------------------------------------------------
- * Drawing.
- */
-
- /* Clear the texture by filling it with all zeroes.
- *
- * This call might happen in parallel with draw, but can never happen in parallel with the
- * update.
- *
- * The actual zeroing can be deferred to a later moment. What is important is that after clear
- * and before pixels update the drawing texture will be fully empty, and that partial update
- * after clear will write new pixel values for an updating area, leaving everything else zeroed.
- *
- * If the GPU display supports graphics interoperability then the zeroing the display is to be
- * delegated to the device via the `DeviceGraphicsInteropDestination`. */
- virtual void clear() = 0;
-
- /* Draw the current state of the texture.
- *
- * Returns true if this call did draw an updated state of the texture. */
- bool draw();
-
- protected:
- /* Implementation-specific calls which subclasses are to implement.
- * These `do_foo()` method corresponds to their `foo()` calls, but they are purely virtual to
- * simplify their particular implementation. */
- virtual bool do_update_begin(const GPUDisplayParams &params,
- int texture_width,
- int texture_height) = 0;
- virtual void do_update_end() = 0;
-
- virtual void do_copy_pixels_to_texture(const half4 *rgba_pixels,
- int texture_x,
- int texture_y,
- int pixels_width,
- int pixels_height) = 0;
-
- virtual half4 *do_map_texture_buffer() = 0;
- virtual void do_unmap_texture_buffer() = 0;
-
- /* Note that this might be called in parallel to do_update_begin() and do_update_end(),
- * the subclass is responsible for appropriate mutex locks to avoid multiple threads
- * editing and drawing the texture at the same time. */
- virtual void do_draw(const GPUDisplayParams &params) = 0;
-
- virtual DeviceGraphicsInteropDestination do_graphics_interop_get() = 0;
-
- private:
- thread_mutex mutex_;
- GPUDisplayParams params_;
-
- /* Mark texture as its content has been updated.
- * Used from places which knows that the texture content has been brought up-to-date, so that the
- * drawing knows whether it can be performed, and whether drawing happened with an up-to-date
- * texture state. */
- void mark_texture_updated();
-
- /* State of the update process. */
- struct {
- /* True when update is in process, indicated by `update_begin()` / `update_end()`. */
- bool is_active = false;
- } update_state_;
-
- /* 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;
-
- /* Texture size in pixels. */
- int2 size = make_int2(0, 0);
- } texture_state_;
-
- /* State of the texture buffer. Is tracked to perform sanity checks. */
- struct {
- /* True when the texture buffer is mapped with `map_texture_buffer()`. */
- bool is_mapped = false;
- } texture_buffer_state_;
-};
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/graph.cpp b/intern/cycles/render/graph.cpp
deleted file mode 100644
index e9da48b624d..00000000000
--- a/intern/cycles/render/graph.cpp
+++ /dev/null
@@ -1,1237 +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)) {
- num_closures += 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 72fc612c0c0..00000000000
--- a/intern/cycles/render/hair.cpp
+++ /dev/null
@@ -1,542 +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/scene.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)
-{
- curvekey_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;
- }
-
- 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,
- float4 *curve_data,
- size_t curvekey_offset)
-{
- 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 */
- size_t curve_num = num_curves();
-
- 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);
-
- curve_data[i] = make_float4(__int_as_float(curve.first_key + curvekey_offset),
- __int_as_float(curve.num_keys),
- __int_as_float(shader_id),
- 0.0f);
- }
-}
-
-void Hair::pack_primitives(PackedBVH *pack, int object, uint visibility, PackFlags pack_flags)
-{
- if (curve_first_key.empty())
- return;
-
- /* Separate loop as other arrays are not initialized if their packing is not required. */
- if ((pack_flags & PACK_VISIBILITY) != 0) {
- unsigned int *prim_visibility = &pack->prim_visibility[optix_prim_offset];
-
- size_t index = 0;
- for (size_t j = 0; j < num_curves(); ++j) {
- Curve curve = get_curve(j);
- for (size_t k = 0; k < curve.num_segments(); ++k, ++index) {
- prim_visibility[index] = visibility;
- }
- }
- }
-
- if ((pack_flags & PACK_GEOMETRY) != 0) {
- unsigned int *prim_tri_index = &pack->prim_tri_index[optix_prim_offset];
- int *prim_type = &pack->prim_type[optix_prim_offset];
- int *prim_index = &pack->prim_index[optix_prim_offset];
- int *prim_object = &pack->prim_object[optix_prim_offset];
- // 'pack->prim_time' is unused by Embree and OptiX
-
- uint type = 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);
-
- size_t index = 0;
- for (size_t j = 0; j < num_curves(); ++j) {
- Curve curve = get_curve(j);
- for (size_t k = 0; k < curve.num_segments(); ++k, ++index) {
- prim_tri_index[index] = -1;
- prim_type[index] = PRIMITIVE_PACK_SEGMENT(type, k);
- // Each curve segment points back to its curve index
- prim_index[index] = j + prim_offset;
- prim_object[index] = object;
- }
- }
- }
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/hair.h b/intern/cycles/render/hair.h
deleted file mode 100644
index e4451d70767..00000000000
--- a/intern/cycles/render/hair.h
+++ /dev/null
@@ -1,157 +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
-
-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 curvekey_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, float4 *curve_data, size_t curvekey_offset);
-
- void pack_primitives(PackedBVH *pack,
- int object,
- uint visibility,
- PackFlags pack_flags) override;
-};
-
-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 ae1150fc07b..00000000000
--- a/intern/cycles/render/light.cpp
+++ /dev/null
@@ -1,1148 +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;
- pixels.resize(size);
-
- /* Evaluate shader on device. */
- ShaderEval shader_eval(device, progress);
- shader_eval.eval(
- SHADER_EVAL_BACKGROUND,
- size,
- [&](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<float4> &d_output) {
- /* Copy output to pixel buffer. */
- float4 *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].x;
- pixels[y * width + x].y = d_output_data[y * width + x].y;
- pixels[y * width + x].z = d_output_data[y * width + x].z;
- }
- }
- });
-}
-
-/* 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 fd9879dd5dd..00000000000
--- a/intern/cycles/render/mesh.cpp
+++ /dev/null
@@ -1,857 +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]);
-
- 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(const vector<uint> &tri_prim_index,
- uint4 *tri_vindex,
- uint *tri_patch,
- float2 *tri_patch_uv,
- size_t vert_offset,
- size_t tri_offset)
-{
- 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++) {
- 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,
- tri_prim_index[i + tri_offset]);
-
- tri_patch[i] = (!get_num_subd_faces()) ? -1 : (triangle_patch[i] * 8 + patch_offset);
- }
-}
-
-void Mesh::pack_patches(uint *patch_data, uint vert_offset, uint face_offset, uint corner_offset)
-{
- 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++;
- }
- }
-}
-
-void Mesh::pack_primitives(ccl::PackedBVH *pack, int object, uint visibility, PackFlags pack_flags)
-{
- if (triangles.empty())
- return;
-
- const size_t num_prims = num_triangles();
-
- /* Use prim_offset for indexing as it is computed per geometry type, and prim_tri_verts does not
- * contain data for Hair geometries. */
- float4 *prim_tri_verts = &pack->prim_tri_verts[prim_offset * 3];
- // 'pack->prim_time' is unused by Embree and OptiX
-
- uint type = has_motion_blur() ? PRIMITIVE_MOTION_TRIANGLE : PRIMITIVE_TRIANGLE;
-
- /* Separate loop as other arrays are not initialized if their packing is not required. */
- if ((pack_flags & PackFlags::PACK_VISIBILITY) != 0) {
- unsigned int *prim_visibility = &pack->prim_visibility[optix_prim_offset];
- for (size_t k = 0; k < num_prims; ++k) {
- prim_visibility[k] = visibility;
- }
- }
-
- if ((pack_flags & PackFlags::PACK_GEOMETRY) != 0) {
- /* Use optix_prim_offset for indexing as those arrays also contain data for Hair geometries. */
- unsigned int *prim_tri_index = &pack->prim_tri_index[optix_prim_offset];
- int *prim_type = &pack->prim_type[optix_prim_offset];
- int *prim_index = &pack->prim_index[optix_prim_offset];
- int *prim_object = &pack->prim_object[optix_prim_offset];
-
- for (size_t k = 0; k < num_prims; ++k) {
- if ((pack_flags & PackFlags::PACK_GEOMETRY) != 0) {
- prim_tri_index[k] = (prim_offset + k) * 3;
- prim_type[k] = type;
- prim_index[k] = prim_offset + k;
- prim_object[k] = object;
- }
- }
- }
-
- if ((pack_flags & PackFlags::PACK_VERTICES) != 0) {
- for (size_t k = 0; k < num_prims; ++k) {
- const Mesh::Triangle t = get_triangle(k);
- prim_tri_verts[k * 3] = float3_to_float4(verts[t.v[0]]);
- prim_tri_verts[k * 3 + 1] = float3_to_float4(verts[t.v[1]]);
- prim_tri_verts[k * 3 + 2] = float3_to_float4(verts[t.v[2]]);
- }
- }
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/mesh.h b/intern/cycles/render/mesh.h
deleted file mode 100644
index e9e79f7f20d..00000000000
--- a/intern/cycles/render/mesh.h
+++ /dev/null
@@ -1,267 +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(const vector<uint> &tri_prim_index,
- uint4 *tri_vindex,
- uint *tri_patch,
- float2 *tri_patch_uv,
- size_t vert_offset,
- size_t tri_offset);
- void pack_patches(uint *patch_data, uint vert_offset, uint face_offset, uint corner_offset);
-
- void pack_primitives(PackedBVH *pack,
- int object,
- uint visibility,
- PackFlags pack_flags) 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 c00c4c24211..00000000000
--- a/intern/cycles/render/mesh_displace.cpp
+++ /dev/null
@@ -1,409 +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<float4> &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 float4 *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 = float4_to_float3(d_output_data[d_output_index++]);
- /* 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, DeviceScene *dscene, 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;
- }
- }
-
- /* Needs to be up to data for attribute access. */
- device->const_copy_to("__data", &dscene->data, sizeof(dscene->data));
-
- /* Evaluate shader on device. */
- ShaderEval shader_eval(device, progress);
- if (!shader_eval.eval(SHADER_EVAL_DISPLACE,
- num_verts,
- 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 90f70cf19ec..00000000000
--- a/intern/cycles/render/nodes.cpp
+++ /dev/null
@@ -1,7091 +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("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("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. */
-}
-
-/* Curve 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");
-}
-
-/* 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 22bdb06b059..00000000000
--- a/intern/cycles/render/nodes.h
+++ /dev/null
@@ -1,1557 +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 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 4637f8fe989..00000000000
--- a/intern/cycles/render/object.cpp
+++ /dev/null
@@ -1,977 +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;
- 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;
-}
-
-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;
-
- /* 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 c52ddce48da..00000000000
--- a/intern/cycles/render/object.h
+++ /dev/null
@@ -1,186 +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;
-
- 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 5a43b641872..00000000000
--- a/intern/cycles/render/osl.cpp
+++ /dev/null
@@ -1,1304 +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::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 */
- 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 whitespace */
- 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 whitespace */
- 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/render/osl.h b/intern/cycles/render/osl.h
deleted file mode 100644
index dfeec54d915..00000000000
--- a/intern/cycles/render/osl.h
+++ /dev/null
@@ -1,198 +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 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/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 27ad7c0db97..00000000000
--- a/intern/cycles/render/pass.cpp
+++ /dev/null
@@ -1,427 +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("render_time", PASS_RENDER_TIME);
- 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_RENDER_TIME:
- /* This pass is handled entirely on the host side. */
- pass_info.num_components = 0;
- 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 a4b030190dc..00000000000
--- a/intern/cycles/render/scene.cpp
+++ /dev/null
@@ -1,912 +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_tri_index(device, "__prim_tri_index", MEM_GLOBAL),
- prim_tri_verts(device, "__prim_tri_verts", 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_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),
- 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) {
- 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();
-}
-
-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);
- }
-
- 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;
-}
-
-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 cf4a3ba6b12..00000000000
--- a/intern/cycles/render/scene.h
+++ /dev/null
@@ -1,409 +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<uint> prim_tri_index;
- device_vector<float4> prim_tri_verts;
- 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<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<float4> curves;
- device_vector<float4> curve_keys;
-
- 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();
-
- 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();
-
- 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 269d67e8bda..00000000000
--- a/intern/cycles/render/session.cpp
+++ /dev/null
@@ -1,743 +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/gpu_display.h"
-#include "render/graph.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 "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_->tile_buffer_update_cb = [&]() {
- if (!update_render_tile_cb) {
- return;
- }
- update_render_tile_cb();
- };
- path_trace_->tile_buffer_write_cb = [&]() {
- if (!write_render_tile_cb) {
- return;
- }
- write_render_tile_cb();
- };
- path_trace_->tile_buffer_read_cb = [&]() -> bool {
- if (!read_render_tile_cb) {
- return false;
- }
- read_render_tile_cb();
- return true;
- };
- 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();
-
- /* TODO(sergey): Bring the passes in viewport back.
- * It is unclear why there is such an exception needed though. */
-#if 0
- if (buffers && params.write_render_cb) {
- /* Copy to display buffer and write out image if requested */
- delete display;
-
- display = new DisplayBuffer(device, false);
- display->reset(buffers->params);
- copy_to_display_buffer(params.samples);
-
- int w = display->draw_width;
- int h = display->draw_height;
- uchar4 *pixels = display->rgba_byte.copy_from_device(0, w, h);
- params.write_render_cb((uchar *)pixels, w, h, 4);
- }
-#endif
-
- /* 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_gpu_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;
- }
-
- {
- /* 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();
-
- if (device->have_error()) {
- const string &error_message = device->error_message();
- progress.set_error(error_message);
- progress.set_cancel(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.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_gpu_display(unique_ptr<GPUDisplay> gpu_display)
-{
- path_trace_->set_gpu_display(move(gpu_display));
-}
-
-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);
- }
-}
-
-/* --------------------------------------------------------------------
- * Tile and tile pixels access.
- */
-
-bool Session::has_multiple_render_tiles() const
-{
- return tile_manager_.has_multiple_tiles();
-}
-
-int2 Session::get_render_tile_size() const
-{
- return path_trace_->get_render_tile_size();
-}
-
-int2 Session::get_render_tile_offset() const
-{
- return path_trace_->get_render_tile_offset();
-}
-
-string_view Session::get_render_tile_layer() const
-{
- const BufferParams &buffer_params = path_trace_->get_render_tile_params();
- return buffer_params.layer;
-}
-
-string_view Session::get_render_tile_view() const
-{
- const BufferParams &buffer_params = path_trace_->get_render_tile_params();
- return buffer_params.view;
-}
-
-bool Session::copy_render_tile_from_device()
-{
- return path_trace_->copy_render_tile_from_device();
-}
-
-bool Session::get_render_tile_pixels(const string &pass_name, int num_components, float *pixels)
-{
- /* NOTE: The code relies on a fact that session is fully update and no scene/buffer modification
- * is happening while this function runs. */
-
- const BufferParams &buffer_params = path_trace_->get_render_tile_params();
-
- const BufferPass *pass = buffer_params.find_pass(pass_name);
- if (pass == nullptr) {
- return false;
- }
-
- const bool has_denoised_result = path_trace_->has_denoised_result();
- if (pass->mode == PassMode::DENOISED && !has_denoised_result) {
- pass = buffer_params.find_pass(pass->type);
- if (pass == nullptr) {
- /* Happens when denoised result pass is requested but is never written by the kernel. */
- return false;
- }
- }
-
- pass = buffer_params.get_actual_display_pass(pass);
-
- const float exposure = buffer_params.exposure;
- const int num_samples = path_trace_->get_num_render_tile_samples();
-
- PassAccessor::PassAccessInfo pass_access_info(*pass);
- pass_access_info.use_approximate_shadow_catcher = buffer_params.use_approximate_shadow_catcher;
- pass_access_info.use_approximate_shadow_catcher_background =
- pass_access_info.use_approximate_shadow_catcher && !buffer_params.use_transparent_background;
-
- const PassAccessorCPU pass_accessor(pass_access_info, exposure, num_samples);
- const PassAccessor::Destination destination(pixels, num_components);
-
- return path_trace_->get_render_tile_pixels(pass_accessor, destination);
-}
-
-bool Session::set_render_tile_pixels(const string &pass_name,
- int num_components,
- const float *pixels)
-{
- /* NOTE: The code relies on a fact that session is fully update and no scene/buffer modification
- * is happening while this function runs. */
-
- const BufferPass *pass = buffer_params_.find_pass(pass_name);
- if (!pass) {
- return false;
- }
-
- const float exposure = scene->film->get_exposure();
- const int num_samples = render_scheduler_.get_num_rendered_samples();
-
- const PassAccessor::PassAccessInfo pass_access_info(*pass);
- PassAccessorCPU pass_accessor(pass_access_info, exposure, num_samples);
- PassAccessor::Source source(pixels, num_components);
-
- return path_trace_->set_render_tile_pixels(pass_accessor, source);
-}
-
-/* --------------------------------------------------------------------
- * 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 e3056e7778b..00000000000
--- a/intern/cycles/render/session.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.
- */
-
-#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 PathTrace;
-class Progress;
-class GPUDisplay;
-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;
-
- function<bool(const uchar *pixels, int width, int height, int channels)> write_render_cb;
-
- 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;
-
- function<void(void)> write_render_tile_cb;
- function<void(void)> update_render_tile_cb;
- function<void(void)> read_render_tile_cb;
-
- /* 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_gpu_display(unique_ptr<GPUDisplay> gpu_display);
-
- 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);
-
- /* --------------------------------------------------------------------
- * Tile and tile pixels access.
- */
-
- bool has_multiple_render_tiles() const;
-
- /* Get size and offset (relative to the buffer's full x/y) of the currently rendering tile. */
- int2 get_render_tile_size() const;
- int2 get_render_tile_offset() const;
-
- string_view get_render_tile_layer() const;
- string_view get_render_tile_view() const;
-
- bool copy_render_tile_from_device();
-
- bool get_render_tile_pixels(const string &pass_name, int num_components, float *pixels);
- bool set_render_tile_pixels(const string &pass_name, int num_components, const float *pixels);
-
- /* --------------------------------------------------------------------
- * 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 23786a3390f..00000000000
--- a/intern/cycles/render/shader.cpp
+++ /dev/null
@@ -1,876 +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::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/render/shader.h b/intern/cycles/render/shader.h
deleted file mode 100644
index 5f9adea3949..00000000000
--- a/intern/cycles/render/shader.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 __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;
- }
-
- /* 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 2379eb775a0..00000000000
--- a/intern/cycles/render/svm.cpp
+++ /dev/null
@@ -1,984 +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*/)
-{
-}
-
-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/render/svm.h b/intern/cycles/render/svm.h
deleted file mode 100644
index 0353c393ae4..00000000000
--- a/intern/cycles/render/svm.h
+++ /dev/null
@@ -1,238 +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 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/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 4ab2e856c5d..00000000000
--- a/intern/cycles/render/tile.cpp
+++ /dev/null
@@ -1,591 +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();
- node_to_image_spec_atttributes(
- &write_state_.image_spec, &denoise_params, ATTR_DENOISE_SOCKET_PREFIX);
-}
-
-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_y = index / tile_state_.num_tiles_x;
- const int tile_x = index - tile_y * tile_state_.num_tiles_x;
-
- Tile tile;
-
- tile.x = tile_x * tile_size_.x;
- tile.y = tile_y * tile_size_.y;
- tile.width = tile_size_.x;
- tile.height = tile_size_.y;
-
- tile.width = min(tile.width, buffer_params_.width - tile.x);
- tile.height = min(tile.height, buffer_params_.height - tile.y);
-
- return tile;
-}
-
-const Tile &TileManager::get_current_tile() const
-{
- return tile_state_.current_tile;
-}
-
-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);
-
- const BufferParams &tile_params = tile_buffers.params;
-
- const float *pixels = tile_buffers.buffer.data();
- const int tile_x = tile_params.full_x - buffer_params_.full_x;
- const int tile_y = tile_params.full_y - buffer_params_.full_y;
-
- 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.width,
- tile_y,
- tile_y + tile_params.height,
- 0,
- 1,
- TypeDesc::FLOAT,
- pixels)) {
- 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);
-
- VLOG(3) << "Write dummy tile at " << tile.x << ", " << tile.y;
-
- write_state_.tile_out->write_tiles(tile.x,
- tile.x + tile.width,
- tile.y,
- tile.y + tile.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 8392274ff79..00000000000
--- a/intern/cycles/render/tile.h
+++ /dev/null
@@ -1,170 +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;
-
- 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;
- }
-
- bool next();
- bool done();
-
- const Tile &get_current_tile() 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);
-
- 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..6f8b97a4998
--- /dev/null
+++ b/intern/cycles/scene/CMakeLists.txt
@@ -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.
+
+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
+ pointcloud.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
+ pointcloud.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..a8aec133fb6
--- /dev/null
+++ b/intern/cycles/scene/alembic.cpp
@@ -0,0 +1,1535 @@
+/*
+ * 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/pointcloud.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();
+ points.clear();
+ radiuses.clear();
+ points_shader.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)
+ CHECK_IF_CONSTANT(points)
+ CHECK_IF_CONSTANT(radiuses)
+ CHECK_IF_CONSTANT(points_shader)
+
+ 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();
+ points.invalidate_last_loaded_time();
+ radiuses.invalidate_last_loaded_time();
+ points_shader.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);
+ points.set_time_sampling(time_sampling);
+ radiuses.set_time_sampling(time_sampling);
+ points_shader.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();
+ mem_used += points.memory_used();
+ mem_used += radiuses.memory_used();
+ mem_used += points_shader.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_STRING_ARRAY(layers, "Layers", array<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() || filepath_is_modified() || layers_is_modified()) {
+ Alembic::AbcCoreFactory::IFactory factory;
+ factory.setPolicy(Alembic::Abc::ErrorHandler::kQuietNoopPolicy);
+
+ std::vector<std::string> filenames;
+ filenames.push_back(filepath.c_str());
+
+ for (const ustring &layer : layers) {
+ filenames.push_back(layer.c_str());
+ }
+
+ /* We need to reverse the order as overriding archives should come first. */
+ std::reverse(filenames.begin(), filenames.end());
+
+ archive = factory.getArchive(filenames);
+
+ if (!archive.valid()) {
+ /* avoid potential infinite update loops in viewport synchronization */
+ filepath.clear();
+ layers.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::POINTS) {
+ read_points(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::POINTS) {
+ geometry = scene_->create_node<PointCloud>();
+ }
+ 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());
+
+ cached_data.subd_vertex_crease_indices.copy_to_socket(
+ frame_time, mesh, mesh->get_subd_vert_creases_socket());
+
+ cached_data.subd_vertex_crease_weights.copy_to_socket(
+ frame_time, mesh, mesh->get_subd_vert_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::read_points(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;
+ }
+
+ PointCloud *point_cloud = static_cast<PointCloud *>(object->get_geometry());
+
+ /* Make sure shader ids are also updated. */
+ if (point_cloud->used_shaders_is_modified()) {
+ point_cloud->tag_shader_modified();
+ }
+
+ cached_data.points.copy_to_socket(frame_time, point_cloud, point_cloud->get_points_socket());
+ cached_data.radiuses.copy_to_socket(frame_time, point_cloud, point_cloud->get_radius_socket());
+ cached_data.points_shader.copy_to_socket(
+ frame_time, point_cloud, point_cloud->get_shader_socket());
+
+ /* update attributes */
+
+ update_attributes(point_cloud->attributes, cached_data, frame_time);
+
+ const bool rebuild = (point_cloud->points_is_modified() || point_cloud->radius_is_modified() ||
+ point_cloud->shader_is_modified());
+ point_cloud->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)) {
+ IPoints points(parent, header.getName());
+
+ unordered_map<std::string, AlembicObject *>::const_iterator iter;
+ iter = object_map.find(points.getFullName());
+
+ if (iter != object_map.end()) {
+ AlembicObject *abc_object = iter->second;
+ abc_object->iobject = points;
+ abc_object->schema_type = AlembicObject::POINTS;
+
+ 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 = points;
+ }
+ 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::POINTS) {
+ if (!object->has_data_loaded() || default_radius_is_modified() ||
+ object->radius_scale_is_modified()) {
+ IPoints points(object->iobject, Alembic::Abc::kWrapExisting);
+ IPointsSchema schema = points.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..9ea4737bea1
--- /dev/null
+++ b/intern/cycles/scene/alembic.h
@@ -0,0 +1,584 @@
+/*
+ * 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;
+ DataStore<array<int>> subd_vertex_crease_indices;
+ DataStore<array<float>> subd_vertex_crease_weights;
+
+ /* hair data */
+ DataStore<array<float3>> curve_keys;
+ DataStore<array<float>> curve_radius;
+ DataStore<array<int>> curve_first_key;
+ DataStore<array<int>> curve_shader;
+
+ /* point data */
+ DataStore<array<float3>> points;
+ DataStore<array<float>> radiuses;
+ DataStore<array<int>> points_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,
+ POINTS,
+ };
+
+ 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)
+
+ /* Layers for the Alembic archive. Layers are in the order in which they override data, with the
+ * latter elements overriding the former ones. */
+ NODE_SOCKET_API_ARRAY(array<ustring>, layers)
+
+ /* 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 IPoints at the specified frame_time. Creates corresponding Geometry and
+ * Object Nodes in the Cycles scene if none exist yet. */
+ void read_points(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..33908dff6e5
--- /dev/null
+++ b/intern/cycles/scene/alembic_read.cpp
@@ -0,0 +1,1120 @@
+/*
+ * 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_edge_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 add_subd_vertex_creases(CachedData &cached_data,
+ const SubDSchemaData &data,
+ chrono_t time)
+{
+ if (!(data.corner_indices.valid() && data.crease_sharpnesses.valid())) {
+ return;
+ }
+
+ const ISampleSelector iss = ISampleSelector(time);
+ const Int32ArraySamplePtr creases_indices = data.crease_indices.getValue(iss);
+ const FloatArraySamplePtr creases_sharpnesses = data.crease_sharpnesses.getValue(iss);
+
+ if (!(creases_indices && creases_sharpnesses) ||
+ creases_indices->size() != creases_sharpnesses->size()) {
+ return;
+ }
+
+ array<float> sharpnesses;
+ sharpnesses.reserve(creases_indices->size());
+ array<int> indices;
+ indices.reserve(creases_indices->size());
+
+ for (size_t i = 0; i < creases_indices->size(); i++) {
+ indices.push_back_reserved((*creases_indices)[i]);
+ sharpnesses.push_back_reserved((*creases_sharpnesses)[i]);
+ }
+
+ cached_data.subd_vertex_crease_indices.add_data(indices, time);
+ cached_data.subd_vertex_crease_weights.add_data(sharpnesses, 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_edge_creases(cached_data, data, time);
+ add_subd_vertex_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);
+}
+
+/* Points Geometries. */
+
+static void read_points_data(CachedData &cached_data, const PointsSchemaData &data, chrono_t time)
+{
+ const ISampleSelector iss = ISampleSelector(time);
+
+ const P3fArraySamplePtr position = data.positions.getValue(iss);
+ FloatArraySamplePtr radiuses;
+
+ array<float3> a_positions;
+ array<float> a_radius;
+ array<int> a_shader;
+ a_positions.reserve(position->size());
+ a_radius.reserve(position->size());
+ a_shader.reserve(position->size());
+
+ if (data.radiuses.valid()) {
+ IFloatGeomParam::Sample wsample = data.radiuses.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;
+
+ int offset = 0;
+ for (size_t i = 0; i < position->size(); i++) {
+ const V3f &f = position->get()[offset + i];
+ a_positions.push_back_slow(make_float3_from_yup(f));
+
+ if (do_radius) {
+ radius = (*radiuses)[offset + i];
+ a_radius.push_back_slow(radius);
+ }
+
+ a_shader.push_back_slow((int)0);
+ }
+
+ cached_data.points.add_data(a_positions, time);
+ cached_data.radiuses.add_data(a_radius, time);
+ cached_data.points_shader.add_data(a_shader, time);
+}
+
+void read_geometry_data(AlembicProcedural *proc,
+ CachedData &cached_data,
+ const PointsSchemaData &data,
+ Progress &progress)
+{
+ read_data_loop(proc, cached_data, data, read_points_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..94018b82747
--- /dev/null
+++ b/intern/cycles/scene/alembic_read.h
@@ -0,0 +1,155 @@
+/*
+ * 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;
+
+ Alembic::AbcGeom::IInt32ArrayProperty corner_indices;
+ Alembic::AbcGeom::IFloatArrayProperty corner_sharpnesses;
+
+ // Those are unsupported for now.
+ 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);
+
+/* Data of a ICurvesSchema that we need to read. */
+struct PointsSchemaData {
+ Alembic::AbcGeom::TimeSamplingPtr time_sampling;
+ size_t num_samples;
+
+ float default_radius;
+ float radius_scale;
+
+ Alembic::AbcGeom::IP3fArrayProperty positions;
+ Alembic::AbcGeom::IInt32ArrayProperty num_points;
+ Alembic::AbcGeom::IFloatGeomParam radiuses;
+ // Those are unsupported for now.
+ Alembic::AbcGeom::IV3fArrayProperty velocities;
+};
+
+void read_geometry_data(AlembicProcedural *proc,
+ CachedData &cached_data,
+ const PointsSchemaData &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..f1021a26e8a
--- /dev/null
+++ b/intern/cycles/scene/attribute.cpp
@@ -0,0 +1,933 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "scene/pointcloud.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();
+ }
+ }
+ else if (geom->geometry_type == Geometry::POINTCLOUD) {
+ PointCloud *pointcloud = static_cast<PointCloud *>(geom);
+ size = pointcloud->num_points();
+ }
+ 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);
+ }
+ }
+ else if (geom->geometry_type == Geometry::POINTCLOUD) {
+ PointCloud *pointcloud = static_cast<PointCloud *>(geom);
+ size = pointcloud->num_points() * (pointcloud->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_POINT_RANDOM:
+ return "point_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;
+ }
+
+ if (attr.type == TypeFloat4 || attr.type == TypeRGBA || attr.type == TypeDesc::TypeMatrix) {
+ return AttrKernelDataType::FLOAT4;
+ }
+
+ 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::POINTCLOUD) {
+ switch (std) {
+ case ATTR_STD_UV:
+ attr = add(name, TypeFloat2, ATTR_ELEMENT_VERTEX);
+ break;
+ case ATTR_STD_GENERATED:
+ attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX);
+ break;
+ case ATTR_STD_MOTION_VERTEX_POSITION:
+ attr = add(name, TypeDesc::TypeFloat4, ATTR_ELEMENT_VERTEX_MOTION);
+ break;
+ case ATTR_STD_POINT_RANDOM:
+ attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_VERTEX);
+ break;
+ case ATTR_STD_GENERATED_TRANSFORM:
+ attr = add(name, TypeDesc::TypeMatrix, ATTR_ELEMENT_MESH);
+ 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::TypeFloat4, 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..612a0b7c80d
--- /dev/null
+++ b/intern/cycles/scene/attribute.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 __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, FLOAT4 = 3, UCHAR4 = 4, NUM = 5 };
+
+/* 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..2f3b55f887f
--- /dev/null
+++ b/intern/cycles/scene/camera.cpp
@@ -0,0 +1,828 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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);
+ panorama_type_enum.insert("fisheye_lens_polynomial", PANORAMA_FISHEYE_LENS_POLYNOMIAL);
+ 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);
+
+ SOCKET_FLOAT(fisheye_polynomial_k0, "Fisheye Polynomial K0", 0.0f);
+ SOCKET_FLOAT(fisheye_polynomial_k1, "Fisheye Polynomial K1", 0.0f);
+ SOCKET_FLOAT(fisheye_polynomial_k2, "Fisheye Polynomial K2", 0.0f);
+ SOCKET_FLOAT(fisheye_polynomial_k3, "Fisheye Polynomial K3", 0.0f);
+ SOCKET_FLOAT(fisheye_polynomial_k4, "Fisheye Polynomial K4", 0.0f);
+
+ 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);
+ kcam->fisheye_lens_polynomial_bias = fisheye_polynomial_k0;
+ kcam->fisheye_lens_polynomial_coefficients = make_float4(
+ fisheye_polynomial_k1, fisheye_polynomial_k2, fisheye_polynomial_k3, fisheye_polynomial_k4);
+
+ 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..50586287bea
--- /dev/null
+++ b/intern/cycles/scene/camera.h
@@ -0,0 +1,242 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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)
+
+ NODE_SOCKET_API(float, fisheye_polynomial_k0)
+ NODE_SOCKET_API(float, fisheye_polynomial_k1)
+ NODE_SOCKET_API(float, fisheye_polynomial_k2)
+ NODE_SOCKET_API(float, fisheye_polynomial_k3)
+ NODE_SOCKET_API(float, fisheye_polynomial_k4)
+
+ /* 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..f0b7eb724de
--- /dev/null
+++ b/intern/cycles/scene/colorspace.cpp
@@ -0,0 +1,459 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_rgba(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);
+ }
+ }
+}
+
+template<typename T, bool compress_as_srgb = false>
+inline void processor_apply_pixels_grayscale(const OCIO::Processor *processor,
+ T *pixels,
+ size_t num_pixels)
+{
+ 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<float> float_pixels(chunk_size * 3);
+
+ for (size_t j = 0; j < num_pixels; j += chunk_size) {
+ size_t width = std::min(chunk_size, num_pixels - j);
+
+ /* Convert to 3 channels, since that's the minimum required by OpenColorIO. */
+ {
+ const T *pixel = pixels + j;
+ float *fpixel = float_pixels.data();
+ for (size_t i = 0; i < width; i++, pixel++, fpixel += 3) {
+ const float f = util_image_cast_to_float<T>(*pixel);
+ fpixel[0] = f;
+ fpixel[1] = f;
+ fpixel[2] = f;
+ }
+ }
+
+ OCIO::PackedImageDesc desc((float *)float_pixels.data(), width, 1, 3);
+ device_processor->apply(desc);
+
+ {
+ T *pixel = pixels + j;
+ const float *fpixel = float_pixels.data();
+ for (size_t i = 0; i < width; i++, pixel++, fpixel += 3) {
+ float f = average(make_float3(fpixel[0], fpixel[1], fpixel[2]));
+ if (compress_as_srgb) {
+ f = color_linear_to_srgb(f);
+ }
+ *pixel = util_image_cast_from_float<T>(f);
+ }
+ }
+ }
+}
+
+#endif
+
+template<typename T>
+void ColorSpaceManager::to_scene_linear(
+ ustring colorspace, T *pixels, size_t num_pixels, bool is_rgba, bool compress_as_srgb)
+{
+#ifdef WITH_OCIO
+ const OCIO::Processor *processor = (const OCIO::Processor *)get_processor(colorspace);
+
+ if (processor) {
+ if (is_rgba) {
+ if (compress_as_srgb) {
+ /* Compress output as sRGB. */
+ processor_apply_pixels_rgba<T, true>(processor, pixels, num_pixels);
+ }
+ else {
+ /* Write output as scene linear directly. */
+ processor_apply_pixels_rgba<T>(processor, pixels, num_pixels);
+ }
+ }
+ else {
+ if (compress_as_srgb) {
+ /* Compress output as sRGB. */
+ processor_apply_pixels_grayscale<T, true>(processor, pixels, num_pixels);
+ }
+ else {
+ /* Write output as scene linear directly. */
+ processor_apply_pixels_grayscale<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 == 1) {
+ float3 rgb = make_float3(pixel[0], pixel[0], pixel[0]);
+ device_processor->applyRGB(&rgb.x);
+ pixel[0] = average(rgb);
+ }
+ 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, bool);
+template void ColorSpaceManager::to_scene_linear(ustring, ushort *, size_t, bool, bool);
+template void ColorSpaceManager::to_scene_linear(ustring, half *, size_t, bool, bool);
+template void ColorSpaceManager::to_scene_linear(ustring, float *, size_t, bool, bool);
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/scene/colorspace.h b/intern/cycles/scene/colorspace.h
new file mode 100644
index 00000000000..f02c1231a44
--- /dev/null
+++ b/intern/cycles/scene/colorspace.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 is_rgba, 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..e9fb3426b70
--- /dev/null
+++ b/intern/cycles/scene/constant_fold.cpp
@@ -0,0 +1,455 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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(3) << "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(3) << "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(3) << "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(3) << "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 (
+ /* Can't constant fold since we always need to normalize the output. */
+ (type != NODE_MAPPING_TYPE_NORMAL) &&
+ /* Check all use values are zero, note location is not used by vector and normal types. */
+ (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..cdaaea6be2f
--- /dev/null
+++ b/intern/cycles/scene/film.cpp
@@ -0,0 +1,690 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_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_DIFFUSE && pass_type <= PASS_VOLUME_INDIRECT) {
+ 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..90f1e1cb021
--- /dev/null
+++ b/intern/cycles/scene/geometry.cpp
@@ -0,0 +1,2222 @@
+/*
+ * 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/pointcloud.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_METAL || layout == BVH_LAYOUT_MULTI_OPTIX_EMBREE ||
+ layout == BVH_LAYOUT_MULTI_METAL || layout == BVH_LAYOUT_MULTI_METAL_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.use_compact_structure = params->use_bvh_compact_structure;
+ 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.num_motion_point_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_float4_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_float4_size += size * 4;
+ }
+ else if (mattr->type == TypeFloat4 || mattr->type == TypeRGBA) {
+ *attr_float4_size += size;
+ }
+ 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<packed_float3> &attr_float3,
+ size_t &attr_float3_offset,
+ device_vector<float4> &attr_float4,
+ size_t &attr_float4_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_float4_offset;
+
+ assert(attr_float4.size() >= offset + size * 3);
+ if (mattr->modified) {
+ for (size_t k = 0; k < size * 3; k++) {
+ attr_float4[offset + k] = (&tfm->x)[k];
+ }
+ }
+ attr_float4_offset += size * 3;
+ }
+ else if (mattr->type == TypeFloat4 || mattr->type == TypeRGBA) {
+ float4 *data = mattr->data_float4();
+ offset = attr_float4_offset;
+
+ assert(attr_float4.size() >= offset + size);
+ if (mattr->modified) {
+ for (size_t k = 0; k < size; k++) {
+ attr_float4[offset + k] = data[k];
+ }
+ }
+ attr_float4_offset += size;
+ }
+ else {
+ float3 *data = mattr->data_float3();
+ 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 if (geom->is_pointcloud()) {
+ if (element == ATTR_ELEMENT_VERTEX)
+ offset -= geom->prim_offset;
+ else if (element == ATTR_ELEMENT_VERTEX_MOTION)
+ offset -= geom->prim_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_float4_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_float4_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_float4_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_float4_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_float4.alloc(attr_float4_size);
+ dscene->attributes_uchar4.alloc(attr_uchar4_size);
+
+ /* The order of those flags needs to match that of AttrKernelDataType. */
+ const bool attributes_need_realloc[AttrKernelDataType::NUM] = {
+ dscene->attributes_float.need_realloc(),
+ dscene->attributes_float2.need_realloc(),
+ dscene->attributes_float3.need_realloc(),
+ dscene->attributes_float4.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_float4_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_float4,
+ attr_float4_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_float4,
+ attr_float4_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_float4,
+ attr_float4_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_float4.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_geom_offsets(device, dscene, scene);
+}
+
+void GeometryManager::geom_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 point_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();
+ }
+ else if (geom->is_pointcloud()) {
+ PointCloud *pointcloud = static_cast<PointCloud *>(geom);
+
+ prim_offset_changed = (pointcloud->prim_offset != point_size);
+
+ pointcloud->prim_offset = point_size;
+ point_size += pointcloud->num_points();
+ }
+
+ 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 point_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();
+ }
+ else if (geom->is_pointcloud()) {
+ PointCloud *pointcloud = static_cast<PointCloud *>(geom);
+ point_size += pointcloud->num_points();
+ }
+ }
+
+ /* Fill in all the arrays. */
+ if (tri_size != 0) {
+ /* normals */
+ progress.set_status("Updating Mesh", "Computing normals");
+
+ packed_float3 *tri_verts = dscene->tri_verts.alloc(tri_size * 3);
+ uint *tri_shader = dscene->tri_shader.alloc(tri_size);
+ packed_float3 *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 (point_size != 0) {
+ progress.set_status("Updating Mesh", "Copying Point clouds to device");
+
+ float4 *points = dscene->points.alloc(point_size);
+ uint *points_shader = dscene->points_shader.alloc(point_size);
+
+ foreach (Geometry *geom, scene->geometry) {
+ if (geom->is_pointcloud()) {
+ PointCloud *pointcloud = static_cast<PointCloud *>(geom);
+ pointcloud->pack(
+ scene, &points[pointcloud->prim_offset], &points_shader[pointcloud->prim_offset]);
+ if (progress.get_cancel())
+ return;
+ }
+ }
+
+ dscene->points.copy_to_device();
+ dscene->points_shader.copy_to_device();
+ }
+
+ 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.num_motion_point_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 ||
+ bparams.bvh_layout == BVHLayout::BVH_LAYOUT_METAL);
+
+ 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),
+ DEVICE_POINT_DATA_MODIFIED = (1 << 2),
+
+ ATTR_FLOAT_MODIFIED = (1 << 3),
+ ATTR_FLOAT2_MODIFIED = (1 << 4),
+ ATTR_FLOAT3_MODIFIED = (1 << 5),
+ ATTR_FLOAT4_MODIFIED = (1 << 6),
+ ATTR_UCHAR4_MODIFIED = (1 << 7),
+
+ CURVE_DATA_NEED_REALLOC = (1 << 8),
+ MESH_DATA_NEED_REALLOC = (1 << 9),
+ POINT_DATA_NEED_REALLOC = (1 << 10),
+
+ ATTR_FLOAT_NEEDS_REALLOC = (1 << 11),
+ ATTR_FLOAT2_NEEDS_REALLOC = (1 << 12),
+ ATTR_FLOAT3_NEEDS_REALLOC = (1 << 13),
+ ATTR_FLOAT4_NEEDS_REALLOC = (1 << 14),
+
+ ATTR_UCHAR4_NEEDS_REALLOC = (1 << 15),
+
+ ATTRS_NEED_REALLOC = (ATTR_FLOAT_NEEDS_REALLOC | ATTR_FLOAT2_NEEDS_REALLOC |
+ ATTR_FLOAT3_NEEDS_REALLOC | ATTR_FLOAT4_NEEDS_REALLOC |
+ ATTR_UCHAR4_NEEDS_REALLOC),
+ DEVICE_MESH_DATA_NEEDS_REALLOC = (MESH_DATA_NEED_REALLOC | ATTRS_NEED_REALLOC),
+ DEVICE_POINT_DATA_NEEDS_REALLOC = (POINT_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::FLOAT4: {
+ device_update_flags |= ATTR_FLOAT4_MODIFIED;
+ break;
+ }
+ case AttrKernelDataType::UCHAR4: {
+ device_update_flags |= ATTR_UCHAR4_MODIFIED;
+ break;
+ }
+ case AttrKernelDataType::NUM: {
+ 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::FLOAT4)) {
+ device_update_flags |= ATTR_FLOAT4_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 (geom->is_pointcloud()) {
+ PointCloud *pointcloud = static_cast<PointCloud *>(geom);
+
+ if (pointcloud->need_update_rebuild) {
+ device_update_flags |= DEVICE_POINT_DATA_NEEDS_REALLOC;
+ }
+ else if (pointcloud->is_modified()) {
+ device_update_flags |= DEVICE_POINT_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;
+ }
+
+ if (update_flags & (POINT_ADDED | POINT_REMOVED)) {
+ device_update_flags |= DEVICE_POINT_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 |
+ DEVICE_POINT_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 (device_update_flags & DEVICE_POINT_DATA_NEEDS_REALLOC) {
+ dscene->points.tag_realloc();
+ dscene->points_shader.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_FLOAT4_NEEDS_REALLOC) {
+ dscene->attributes_map.tag_realloc();
+ dscene->attributes_float4.tag_realloc();
+ }
+ else if (device_update_flags & ATTR_FLOAT4_MODIFIED) {
+ dscene->attributes_float4.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();
+ }
+
+ if (device_update_flags & DEVICE_POINT_DATA_MODIFIED) {
+ dscene->points.tag_modified();
+ dscene->points_shader.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()) {
+ /* Geometry-level check for hair shadow transparency.
+ * This matches the logic in the `Hair::update_shadow_transparency()`, avoiding access to
+ * possible non-loaded images. */
+ bool need_shadow_transparency = false;
+ if (geom->geometry_type == Geometry::HAIR) {
+ Hair *hair = static_cast<Hair *>(geom);
+ need_shadow_transparency = hair->need_shadow_transparency();
+ }
+
+ foreach (Node *node, geom->get_used_shaders()) {
+ Shader *shader = static_cast<Shader *>(node);
+ const bool is_true_displacement = (shader->has_displacement &&
+ shader->get_displacement_method() != DISPLACE_BUMP);
+ if (!is_true_displacement && !need_shadow_transparency) {
+ 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());
+ geom_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->points.clear_modified();
+ dscene->points_shader.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_float4.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->points.free_if_need_realloc(force_free);
+ dscene->points_shader.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_float4.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..63ab2c2f4e0
--- /dev/null
+++ b/intern/cycles/scene/geometry.h
@@ -0,0 +1,282 @@
+/*
+ * 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,
+ POINTCLOUD,
+ };
+
+ 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_pointcloud() const
+ {
+ return geometry_type == POINTCLOUD;
+ }
+
+ 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),
+ POINT_ADDED = (1 << 12),
+ POINT_REMOVED = (1 << 13),
+
+ SHADER_ATTRIBUTE_MODIFIED = (1 << 8),
+ SHADER_DISPLACEMENT_MODIFIED = (1 << 9),
+
+ GEOMETRY_ADDED = MESH_ADDED | HAIR_ADDED | POINT_ADDED,
+ GEOMETRY_REMOVED = MESH_REMOVED | HAIR_REMOVED | POINT_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 geom_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<packed_float3> &attr_float3,
+ size_t &attr_float3_offset,
+ device_vector<float4> &attr_float4,
+ size_t &attr_float4_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..7aad46d253c
--- /dev/null
+++ b/intern/cycles/scene/image.cpp
@@ -0,0 +1,913 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_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_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;
+
+ /* Since we don't have information about the exact tile format used in this code location,
+ * just attempt all replacement patterns that Blender supports. */
+ if (tile != 0) {
+ string_replace(tile_filename, "<UDIM>", string_printf("%04d", tile));
+
+ int u = ((tile - 1001) % 10);
+ int v = ((tile - 1001) / 10);
+ string_replace(tile_filename, "<UVTILE>", string_printf("u%d_v%d", u + 1, v + 1));
+ }
+ 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, is_rgba, 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) {
+ if (!image) {
+ /* Image may have been freed due to lack of users. */
+ continue;
+ }
+ 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..7cf09dd6d8f
--- /dev/null
+++ b/intern/cycles/scene/image.h
@@ -0,0 +1,248 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_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..4cea7fbfb01
--- /dev/null
+++ b/intern/cycles/scene/image_oiio.cpp
@@ -0,0 +1,239 @@
+/*
+ * 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) {
+ 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..31901707c35
--- /dev/null
+++ b/intern/cycles/scene/integrator.cpp
@@ -0,0 +1,401 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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/bake.h"
+#include "scene/camera.h"
+#include "scene/film.h"
+#include "scene/integrator.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);
+
+#ifdef WITH_CYCLES_DEBUG
+ static NodeEnum direct_light_sampling_type_enum;
+ direct_light_sampling_type_enum.insert("multiple_importance_sampling",
+ DIRECT_LIGHT_SAMPLING_MIS);
+ direct_light_sampling_type_enum.insert("forward_path_tracing", DIRECT_LIGHT_SAMPLING_FORWARD);
+ direct_light_sampling_type_enum.insert("next_event_estimation", DIRECT_LIGHT_SAMPLING_NEE);
+ SOCKET_ENUM(direct_light_sampling_type,
+ "Direct Light Sampling Type",
+ direct_light_sampling_type_enum,
+ DIRECT_LIGHT_SAMPLING_MIS);
+#endif
+
+ 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_BOOLEAN(use_direct_light, "Use Direct Light", true);
+ SOCKET_BOOLEAN(use_indirect_light, "Use Indirect Light", 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_emission, "Use Emission", true);
+
+ 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_factor != 0.0f) ? ao_bounces : 0;
+ kintegrator->ao_bounces_distance = ao_distance;
+ kintegrator->ao_bounces_factor = ao_factor;
+ kintegrator->ao_additive_factor = ao_additive_factor;
+
+#ifdef WITH_CYCLES_DEBUG
+ kintegrator->direct_light_sampling_type = direct_light_sampling_type;
+#else
+ kintegrator->direct_light_sampling_type = DIRECT_LIGHT_SAMPLING_MIS;
+#endif
+
+ /* 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->filter_closures = 0;
+ if (!use_direct_light) {
+ kintegrator->filter_closures |= FILTER_CLOSURE_DIRECT_LIGHT;
+ }
+ if (!use_indirect_light) {
+ kintegrator->min_bounce = 1;
+ kintegrator->max_bounce = 1;
+ }
+ if (!use_diffuse) {
+ kintegrator->filter_closures |= FILTER_CLOSURE_DIFFUSE;
+ }
+ if (!use_glossy) {
+ kintegrator->filter_closures |= FILTER_CLOSURE_GLOSSY;
+ }
+ if (!use_transmission) {
+ kintegrator->filter_closures |= FILTER_CLOSURE_TRANSMISSION;
+ }
+ if (!use_emission) {
+ kintegrator->filter_closures |= FILTER_CLOSURE_EMISSION;
+ }
+ if (scene->bake_manager->get_baking()) {
+ /* Baking does not need to trace through transparency, we only want to bake
+ * the object itself. */
+ kintegrator->filter_closures |= FILTER_CLOSURE_TRANSPARENT;
+ }
+
+ 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..52f1b296a20
--- /dev/null
+++ b/intern/cycles/scene/integrator.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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)
+
+#ifdef WITH_CYCLES_DEBUG
+ NODE_SOCKET_API(DirectLightSamplingType, direct_light_sampling_type)
+#endif
+
+ 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(bool, use_direct_light);
+ NODE_SOCKET_API(bool, use_indirect_light);
+ NODE_SOCKET_API(bool, use_diffuse);
+ NODE_SOCKET_API(bool, use_glossy);
+ NODE_SOCKET_API(bool, use_transmission);
+ NODE_SOCKET_API(bool, use_emission);
+
+ 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..c381d7a54ff
--- /dev/null
+++ b/intern/cycles/scene/mesh.cpp
@@ -0,0 +1,829 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_vert_creases, "Subdivision Vertex Crease", array<int>());
+ SOCKET_FLOAT_ARRAY(
+ subd_vert_creases_weight, "Subdivision Vertex Crease Weights", array<float>());
+ 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_edge_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::add_vertex_crease(int v, float weight)
+{
+ assert(v < verts.size());
+
+ subd_vert_creases.push_back_slow(v);
+ subd_vert_creases_weight.push_back_slow(weight);
+
+ tag_subd_vert_creases_modified();
+ tag_subd_vert_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(packed_float3 *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_float3(vNi.x, vNi.y, vNi.z);
+ }
+}
+
+void Mesh::pack_verts(packed_float3 *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] = verts[t.v[0]];
+ tri_verts[i * 3 + 1] = verts[t.v[1]];
+ tri_verts[i * 3 + 2] = 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..07acd5328d2
--- /dev/null
+++ b/intern/cycles/scene/mesh.h
@@ -0,0 +1,266 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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)
+
+ NODE_SOCKET_API_ARRAY(array<int>, subd_vert_creases)
+ NODE_SOCKET_API_ARRAY(array<float>, subd_vert_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_edge_crease(int v0, int v1, float weight);
+ void add_vertex_crease(int v, 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(packed_float3 *vnormal);
+ void pack_verts(packed_float3 *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..7c88e310527
--- /dev/null
+++ b/intern/cycles/scene/mesh_subdivision.cpp
@@ -0,0 +1,679 @@
+/*
+ * 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)
+{
+ /* Historical maximum crease weight used at Pixar, influencing the maximum in OpenSubDiv. */
+ static constexpr float CREASE_SCALE = 10.0f;
+
+ size_t num_creases = mesh.get_subd_creases_weight().size();
+ size_t num_vertex_creases = mesh.get_subd_vert_creases().size();
+
+ /* The last loop is over the vertices, so early exit to avoid iterating them needlessly. */
+ if (num_creases == 0 && num_vertex_creases == 0) {
+ return true;
+ }
+
+ 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 * CREASE_SCALE);
+ }
+ }
+
+ std::map<int, float> vertex_creases;
+
+ for (size_t i = 0; i < num_vertex_creases; ++i) {
+ const int vertex_idx = mesh.get_subd_vert_creases()[i];
+ const float weight = mesh.get_subd_vert_creases_weight()[i];
+
+ vertex_creases[vertex_idx] = weight * CREASE_SCALE;
+ }
+
+ for (int i = 0; i < mesh.get_verts().size(); i++) {
+ float sharpness = 0.0f;
+ std::map<int, float>::const_iterator iter = vertex_creases.find(i);
+
+ if (iter != vertex_creases.end()) {
+ sharpness = iter->second;
+ }
+
+ ConstIndexArray vert_edges = getBaseVertexEdges(refiner, i);
+
+ if (vert_edges.size() == 2) {
+ const float sharpness0 = refiner.getLevel(0).getEdgeSharpness(vert_edges[0]);
+ const float sharpness1 = refiner.getLevel(0).getEdgeSharpness(vert_edges[1]);
+
+ sharpness += ccl::min(sharpness0, sharpness1);
+ sharpness = ccl::min(sharpness, CREASE_SCALE);
+ }
+
+ if (sharpness != 0.0f) {
+ 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, (double)u, (double)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..aa0a64f49ec
--- /dev/null
+++ b/intern/cycles/scene/object.cpp
@@ -0,0 +1,1018 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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/pointcloud.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;
+ // bool have_points;
+
+ /* ** 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 || geom->geometry_type == Geometry::POINTCLOUD) {
+ /* 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() :
+ (geom->geometry_type == Geometry::POINTCLOUD) ?
+ static_cast<PointCloud *>(geom)->num_points() :
+ 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_prim_offsets(Device *device, DeviceScene *dscene, Scene *scene)
+{
+ BVHLayoutMask layout_mask = device->get_bvh_layout_mask();
+ if (layout_mask != BVH_LAYOUT_METAL && layout_mask != BVH_LAYOUT_MULTI_METAL &&
+ layout_mask != BVH_LAYOUT_MULTI_METAL_EMBREE) {
+ return;
+ }
+
+ /* On MetalRT, primitive / curve segment offsets can't be baked at BVH build time. Intersection
+ * handlers need to apply the offset manually. */
+ uint *object_prim_offset = dscene->object_prim_offset.alloc(scene->objects.size());
+ foreach (Object *ob, scene->objects) {
+ uint32_t prim_offset = 0;
+ if (Geometry *const geom = ob->geometry) {
+ if (geom->geometry_type == Geometry::HAIR) {
+ prim_offset = ((Hair *const)geom)->curve_segment_offset;
+ }
+ else {
+ prim_offset = geom->prim_offset;
+ }
+ }
+ uint obj_index = ob->get_device_index();
+ object_prim_offset[obj_index] = prim_offset;
+ }
+
+ dscene->object_prim_offset.copy_to_device();
+ dscene->object_prim_offset.clear_modified();
+}
+
+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_geom_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);
+ dscene->object_prim_offset.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..3a97fabbdaa
--- /dev/null
+++ b/intern/cycles/scene/object.h
@@ -0,0 +1,190 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_prim_offsets(Device *device, DeviceScene *dscene, Scene *scene);
+
+ void device_update_flags(Device *device,
+ DeviceScene *dscene,
+ Scene *scene,
+ Progress &progress,
+ bool bounds_valid = true);
+ void device_update_geom_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..0844bff7d4a
--- /dev/null
+++ b/intern/cycles/scene/osl.cpp
@@ -0,0 +1,1316 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 */
+
+ /* Remaining irrelevant bits up to 32. */
+ "__unused__",
+ "__unused__",
+ "__unused__",
+ "__unused__",
+ "__unused__",
+ "__unused__",
+ "__unused__",
+ "__unused__",
+ "__unused__",
+ "__unused__",
+ "__unused__",
+ "__unused__",
+ "__unused__",
+ "__unused__",
+ "__unused__",
+ "__unused__",
+ "__unused__",
+ "__unused__",
+ "__unused__",
+ };
+
+ 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..ca5687e6b4d
--- /dev/null
+++ b/intern/cycles/scene/pass.cpp
@@ -0,0 +1,432 @@
+/*
+ * 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("denoising_previous", PASS_DENOISING_PREVIOUS);
+
+ 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_DENOISING_PREVIOUS:
+ pass_info.num_components = 3;
+ pass_info.use_exposure = true;
+ 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/pointcloud.cpp b/intern/cycles/scene/pointcloud.cpp
new file mode 100644
index 00000000000..4f88fe9db3d
--- /dev/null
+++ b/intern/cycles/scene/pointcloud.cpp
@@ -0,0 +1,304 @@
+/*
+ * 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/pointcloud.h"
+#include "scene/scene.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* PointCloud Point */
+
+void PointCloud::Point::bounds_grow(const float3 *points,
+ const float *radius,
+ BoundBox &bounds) const
+{
+ bounds.grow(points[index], radius[index]);
+}
+
+void PointCloud::Point::bounds_grow(const float3 *points,
+ const float *radius,
+ const Transform &aligned_space,
+ BoundBox &bounds) const
+{
+ float3 P = transform_point(&aligned_space, points[index]);
+ bounds.grow(P, radius[index]);
+}
+
+void PointCloud::Point::bounds_grow(const float4 &point, BoundBox &bounds) const
+{
+ bounds.grow(float4_to_float3(point), point.w);
+}
+
+float4 PointCloud::Point::motion_key(const float3 *points,
+ const float *radius,
+ const float3 *point_steps,
+ size_t num_points,
+ size_t num_steps,
+ float time,
+ size_t p) 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. */
+ const float4 curr_key = point_for_step(
+ points, radius, point_steps, num_points, num_steps, step, p);
+ const float4 next_key = point_for_step(
+ points, radius, point_steps, num_points, num_steps, step + 1, p);
+ /* Interpolate between steps. */
+ return (1.0f - t) * curr_key + t * next_key;
+}
+
+float4 PointCloud::Point::point_for_step(const float3 *points,
+ const float *radius,
+ const float3 *point_steps,
+ size_t num_points,
+ size_t num_steps,
+ size_t step,
+ size_t p) const
+{
+ const size_t center_step = ((num_steps - 1) / 2);
+ if (step == center_step) {
+ /* Center step: regular key location. */
+ return make_float4(points[p].x, points[p].y, points[p].z, radius[p]);
+ }
+ else {
+ /* Center step is not stored in this array. */
+ if (step > center_step) {
+ step--;
+ }
+ const size_t offset = step * num_points;
+ return make_float4(point_steps[offset + p].x,
+ point_steps[offset + p].y,
+ point_steps[offset + p].z,
+ radius[offset + p]);
+ }
+}
+
+/* PointCloud */
+
+NODE_DEFINE(PointCloud)
+{
+ NodeType *type = NodeType::add(
+ "pointcloud", create, NodeType::NONE, Geometry::get_node_base_type());
+
+ SOCKET_POINT_ARRAY(points, "Points", array<float3>());
+ SOCKET_FLOAT_ARRAY(radius, "Radius", array<float>());
+ SOCKET_INT_ARRAY(shader, "Shader", array<int>());
+
+ return type;
+}
+
+PointCloud::PointCloud() : Geometry(node_type, Geometry::POINTCLOUD)
+{
+}
+
+PointCloud::~PointCloud()
+{
+}
+
+void PointCloud::resize(int numpoints)
+{
+ points.resize(numpoints);
+ radius.resize(numpoints);
+ shader.resize(numpoints);
+ attributes.resize();
+
+ tag_points_modified();
+ tag_radius_modified();
+ tag_shader_modified();
+}
+
+void PointCloud::reserve(int numpoints)
+{
+ points.reserve(numpoints);
+ radius.reserve(numpoints);
+ shader.reserve(numpoints);
+ attributes.resize(true);
+}
+
+void PointCloud::clear(const bool preserve_shaders)
+{
+ Geometry::clear(preserve_shaders);
+
+ points.clear();
+ radius.clear();
+ shader.clear();
+ attributes.clear();
+
+ tag_points_modified();
+ tag_radius_modified();
+ tag_shader_modified();
+}
+
+void PointCloud::add_point(float3 co, float r, int shader_index)
+{
+ points.push_back_reserved(co);
+ radius.push_back_reserved(r);
+ shader.push_back_reserved(shader_index);
+
+ tag_points_modified();
+ tag_radius_modified();
+ tag_shader_modified();
+}
+
+void PointCloud::copy_center_to_motion_step(const int motion_step)
+{
+ Attribute *attr_mP = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ if (attr_mP) {
+ float3 *points_data = points.data();
+ size_t numpoints = points.size();
+ memcpy(
+ attr_mP->data_float3() + motion_step * numpoints, points_data, sizeof(float3) * numpoints);
+ }
+}
+
+void PointCloud::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 PointCloud::compute_bounds()
+{
+ BoundBox bnds = BoundBox::empty;
+ size_t numpoints = points.size();
+
+ if (numpoints > 0) {
+ for (size_t i = 0; i < numpoints; i++) {
+ bnds.grow(points[i], radius[i]);
+ }
+
+ Attribute *attr = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+ if (use_motion_blur && attr) {
+ size_t steps_size = points.size() * (motion_steps - 1);
+ float3 *point_steps = attr->data_float3();
+
+ for (size_t i = 0; i < steps_size; i++)
+ bnds.grow(point_steps[i]);
+ }
+
+ if (!bnds.valid()) {
+ bnds = BoundBox::empty;
+
+ /* skip nan or inf coordinates */
+ for (size_t i = 0; i < numpoints; i++)
+ bnds.grow_safe(points[i], radius[i]);
+
+ if (use_motion_blur && attr) {
+ size_t steps_size = points.size() * (motion_steps - 1);
+ float3 *point_steps = attr->data_float3();
+
+ for (size_t i = 0; i < steps_size; i++)
+ bnds.grow_safe(point_steps[i]);
+ }
+ }
+ }
+
+ if (!bnds.valid()) {
+ /* empty mesh */
+ bnds.grow(make_float3(0.0f, 0.0f, 0.0f));
+ }
+
+ bounds = bnds;
+}
+
+void PointCloud::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 < points.size(); i++) {
+ float3 co = transform_point(&tfm, points[i]);
+ float r = radius[i] * scalar;
+
+ /* scale for curve radius is only correct for uniform scale
+ */
+ points[i] = co;
+ radius[i] = r;
+ }
+
+ if (apply_to_motion) {
+ Attribute *attr = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+
+ if (attr) {
+ /* apply transform to motion curve keys */
+ size_t steps_size = points.size() * (motion_steps - 1);
+ float4 *point_steps = attr->data_float4();
+
+ for (size_t i = 0; i < steps_size; i++) {
+ float3 co = transform_point(&tfm, float4_to_float3(point_steps[i]));
+ float radius = point_steps[i].w * scalar;
+
+ /* scale for curve radius is only correct for uniform
+ * scale */
+ point_steps[i] = float3_to_float4(co);
+ point_steps[i].w = radius;
+ }
+ }
+ }
+}
+
+void PointCloud::pack(Scene *scene, float4 *packed_points, uint *packed_shader)
+{
+ size_t numpoints = points.size();
+ float3 *points_data = points.data();
+ float *radius_data = radius.data();
+ int *shader_data = shader.data();
+
+ for (size_t i = 0; i < numpoints; i++) {
+ packed_points[i] = make_float4(
+ points_data[i].x, points_data[i].y, points_data[i].z, radius_data[i]);
+ }
+
+ uint shader_id = 0;
+ uint last_shader = -1;
+ for (size_t i = 0; i < numpoints; i++) {
+ if (last_shader != shader_data[i]) {
+ last_shader = shader_data[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);
+ }
+ packed_shader[i] = shader_id;
+ }
+}
+
+PrimitiveType PointCloud::primitive_type() const
+{
+ return has_motion_blur() ? PRIMITIVE_MOTION_POINT : PRIMITIVE_POINT;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/scene/pointcloud.h b/intern/cycles/scene/pointcloud.h
new file mode 100644
index 00000000000..08987ee6c44
--- /dev/null
+++ b/intern/cycles/scene/pointcloud.h
@@ -0,0 +1,114 @@
+/*
+ * 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
+
+#ifndef __POINTCLOUD_H__
+# define __POINTCLOUD_H__
+
+# include "scene/geometry.h"
+
+CCL_NAMESPACE_BEGIN
+
+class PointCloud : public Geometry {
+ public:
+ NODE_DECLARE
+
+ /* PointCloud Point */
+ struct Point {
+ int index;
+
+ void bounds_grow(const float3 *points, const float *radius, BoundBox &bounds) const;
+ void bounds_grow(const float3 *points,
+ const float *radius,
+ const Transform &aligned_space,
+ BoundBox &bounds) const;
+ void bounds_grow(const float4 &point, BoundBox &bounds) const;
+
+ float4 motion_key(const float3 *points,
+ const float *radius,
+ const float3 *point_steps,
+ size_t num_points,
+ size_t num_steps,
+ float time,
+ size_t p) const;
+ float4 point_for_step(const float3 *points,
+ const float *radius,
+ const float3 *point_steps,
+ size_t num_points,
+ size_t num_steps,
+ size_t step,
+ size_t p) const;
+ };
+
+ NODE_SOCKET_API_ARRAY(array<float3>, points)
+ NODE_SOCKET_API_ARRAY(array<float>, radius)
+ NODE_SOCKET_API_ARRAY(array<int>, shader)
+
+ /* Constructor/Destructor */
+ PointCloud();
+ ~PointCloud();
+
+ /* Geometry */
+ void clear(const bool preserver_shaders = false) override;
+
+ void resize(int numpoints);
+ void reserve(int numpoints);
+ void add_point(float3 loc, float radius, int shader = 0);
+
+ 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;
+
+ /* Points */
+ Point get_point(int i) const
+ {
+ Point point = {i};
+ return point;
+ }
+
+ size_t num_points() const
+ {
+ return points.size();
+ }
+
+ size_t num_attributes() const
+ {
+ return 1;
+ }
+
+ /* UDIM */
+ void get_uv_tiles(ustring map, unordered_set<int> &tiles) override;
+
+ PrimitiveType primitive_type() const override;
+
+ /* BVH */
+ void pack(Scene *scene, float4 *packed_points, uint *packed_shader);
+
+ private:
+ friend class BVH2;
+ friend class BVHBuild;
+ friend class BVHSpatialSplit;
+ friend class DiagSplit;
+ friend class EdgeDice;
+ friend class GeometryManager;
+ friend class ObjectManager;
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __POINTCLOUD_H__ */
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..b5b8eee24a7
--- /dev/null
+++ b/intern/cycles/scene/scene.cpp
@@ -0,0 +1,990 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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/pointcloud.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),
+ points(device, "__points", MEM_GLOBAL),
+ points_shader(device, "__points_shader", 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),
+ object_prim_offset(device, "__object_prim_offset", 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_float4(device, "__attributes_float4", 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 Primitive Offsets");
+ object_manager->device_update_prim_offsets(device, &dscene, this);
+
+ 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;
+ }
+ else if (geom->is_pointcloud()) {
+ kernel_features |= KERNEL_FEATURE_POINTCLOUD;
+ }
+ }
+
+ 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 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 Pointclouds " << string_from_bool(features & KERNEL_FEATURE_POINTCLOUD) << "\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<> PointCloud *Scene::create_node<PointCloud>()
+{
+ PointCloud *node = new PointCloud();
+ node->set_owner(this);
+ geometry.push_back(node);
+ geometry_manager->tag_update(this, GeometryManager::POINT_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(PointCloud *node)
+{
+ delete_node_from_array(geometry, static_cast<Geometry *>(node));
+ geometry_manager->tag_update(this, GeometryManager::POINT_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..77268837070
--- /dev/null
+++ b/intern/cycles/scene/scene.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.
+ */
+
+#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 PointCloud;
+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<packed_float3> tri_verts;
+ device_vector<uint> tri_shader;
+ device_vector<packed_float3> 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;
+
+ /* pointcloud */
+ device_vector<float4> points;
+ device_vector<uint> points_shader;
+
+ /* 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;
+ device_vector<uint> object_prim_offset;
+
+ /* cameras */
+ device_vector<DecomposedTransform> camera_motion;
+
+ /* attributes */
+ device_vector<uint4> attributes_map;
+ device_vector<float> attributes_float;
+ device_vector<float2> attributes_float2;
+ device_vector<packed_float3> attributes_float3;
+ device_vector<float4> attributes_float4;
+ 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_compact_structure;
+ 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_compact_structure = true;
+ 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_compact_structure == params.use_bvh_compact_structure &&
+ 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<> PointCloud *Scene::create_node<PointCloud>();
+
+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(PointCloud *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..34675be8e80
--- /dev/null
+++ b/intern/cycles/scene/shader_nodes.cpp
@@ -0,0 +1,7303 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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/string.h"
+#include "util/transform.h"
+
+#include "kernel/tables.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) {
+ /* OIIO currently does not support <UVTILE> substitutions natively. Replace with a format they
+ * understand. */
+ std::string osl_filename = filename.string();
+ string_replace(osl_filename, "<UVTILE>", "<U>_<V>");
+ compiler.parameter_texture(
+ "filename", ustring(osl_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 ||
+ filename.find("<UVTILE>") != 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);
+
+ int scale_ofs = compiler.stack_assign_if_linked(scale_in);
+ int distortion_ofs = compiler.stack_assign_if_linked(distortion_in);
+ int detail_ofs = compiler.stack_assign_if_linked(detail_in);
+ int dscale_ofs = compiler.stack_assign_if_linked(dscale_in);
+ int droughness_ofs = compiler.stack_assign_if_linked(droughness_in);
+ int phase_ofs = compiler.stack_assign_if_linked(phase_in);
+ int color_ofs = compiler.stack_assign_if_linked(color_out);
+ int fac_ofs = compiler.stack_assign_if_linked(fac_out);
+
+ compiler.add_node(NODE_TEX_WAVE,
+ compiler.encode_uchar4(wave_type, bands_direction, rings_direction, profile),
+ compiler.encode_uchar4(vector_offset, scale_ofs, distortion_ofs),
+ compiler.encode_uchar4(detail_ofs, dscale_ofs, droughness_ofs, phase_ofs));
+
+ compiler.add_node(compiler.encode_uchar4(color_ofs, fac_ofs),
+ __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(3) << "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(3) << "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(3) << "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(3) << "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(3) << "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(3) << "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"));
+
+ int roughness_ofs = compiler.stack_assign_if_linked(roughness_in);
+ int radial_roughness_ofs = compiler.stack_assign_if_linked(radial_roughness_in);
+
+ int normal_ofs = compiler.stack_assign_if_linked(input("Normal"));
+ int offset_ofs = compiler.stack_assign_if_linked(offset_in);
+ int ior_ofs = compiler.stack_assign_if_linked(ior_in);
+
+ int coat_ofs = compiler.stack_assign_if_linked(coat_in);
+ int melanin_ofs = compiler.stack_assign_if_linked(melanin_in);
+ int melanin_redness_ofs = compiler.stack_assign_if_linked(melanin_redness_in);
+
+ ShaderInput *random_in = input("Random");
+ int attr_random = random_in->link ? SVM_STACK_INVALID :
+ compiler.attribute(ATTR_STD_CURVE_RANDOM);
+ int random_in_ofs = compiler.stack_assign_if_linked(random_in);
+ int random_color_ofs = compiler.stack_assign_if_linked(random_color_in);
+ int random_roughness_ofs = compiler.stack_assign_if_linked(random_roughness_in);
+
+ /* Encode all parameters into data nodes. */
+ /* node */
+ compiler.add_node(
+ NODE_CLOSURE_BSDF,
+ /* Socket IDs can be packed 4 at a time into a single data packet */
+ compiler.encode_uchar4(
+ closure, roughness_ofs, radial_roughness_ofs, compiler.closure_mix_weight_offset()),
+ /* The rest are stored as unsigned integers */
+ __float_as_uint(roughness),
+ __float_as_uint(radial_roughness));
+ /* data node */
+ compiler.add_node(normal_ofs,
+ compiler.encode_uchar4(offset_ofs, ior_ofs, color_ofs, parametrization),
+ __float_as_uint(offset),
+ __float_as_uint(ior));
+ /* data node 2 */
+ compiler.add_node(compiler.encode_uchar4(
+ coat_ofs, melanin_ofs, melanin_redness_ofs, absorption_coefficient_ofs),
+ __float_as_uint(coat),
+ __float_as_uint(melanin),
+ __float_as_uint(melanin_redness));
+
+ /* data node 3 */
+ compiler.add_node(
+ compiler.encode_uchar4(tint_ofs, random_in_ofs, random_color_ofs, random_roughness_ofs),
+ __float_as_uint(random),
+ __float_as_uint(random_color),
+ __float_as_uint(random_roughness));
+
+ /* data node 4 */
+ 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");
+ 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));
+ }
+
+ 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");
+}
+
+/* Point Info */
+
+NODE_DEFINE(PointInfoNode)
+{
+ NodeType *type = NodeType::add("point_info", create, NodeType::SHADER);
+
+ SOCKET_OUT_POINT(position, "Position");
+ SOCKET_OUT_FLOAT(radius, "Radius");
+ SOCKET_OUT_FLOAT(random, "Random");
+
+ return type;
+}
+
+PointInfoNode::PointInfoNode() : ShaderNode(get_node_type())
+{
+}
+
+void PointInfoNode::attributes(Shader *shader, AttributeRequestSet *attributes)
+{
+ if (shader->has_surface_link()) {
+ if (!output("Random")->links.empty())
+ attributes->add(ATTR_STD_POINT_RANDOM);
+ }
+
+ ShaderNode::attributes(shader, attributes);
+}
+
+void PointInfoNode::compile(SVMCompiler &compiler)
+{
+ ShaderOutput *out;
+
+ out = output("Position");
+ if (!out->links.empty()) {
+ compiler.add_node(NODE_POINT_INFO, NODE_INFO_POINT_POSITION, compiler.stack_assign(out));
+ }
+
+ out = output("Radius");
+ if (!out->links.empty()) {
+ compiler.add_node(NODE_POINT_INFO, NODE_INFO_POINT_RADIUS, compiler.stack_assign(out));
+ }
+
+ out = output("Random");
+ if (!out->links.empty()) {
+ int attr = compiler.attribute(ATTR_STD_POINT_RANDOM);
+ compiler.add_node(NODE_ATTR, attr, compiler.stack_assign(out), NODE_ATTR_OUTPUT_FLOAT);
+ }
+}
+
+void PointInfoNode::compile(OSLCompiler &compiler)
+{
+ compiler.add(this, "node_point_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");
+}
+
+/* Vector Map Range Node */
+
+NODE_DEFINE(VectorMapRangeNode)
+{
+ NodeType *type = NodeType::add("vector_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_VECTOR(vector, "Vector", zero_float3());
+ SOCKET_IN_VECTOR(from_min, "From_Min_FLOAT3", zero_float3());
+ SOCKET_IN_VECTOR(from_max, "From_Max_FLOAT3", one_float3());
+ SOCKET_IN_VECTOR(to_min, "To_Min_FLOAT3", zero_float3());
+ SOCKET_IN_VECTOR(to_max, "To_Max_FLOAT3", one_float3());
+ SOCKET_IN_VECTOR(steps, "Steps_FLOAT3", make_float3(4.0f));
+ SOCKET_BOOLEAN(use_clamp, "Use Clamp", false);
+
+ SOCKET_OUT_VECTOR(vector, "Vector");
+
+ return type;
+}
+
+VectorMapRangeNode::VectorMapRangeNode() : ShaderNode(get_node_type())
+{
+}
+
+void VectorMapRangeNode::expand(ShaderGraph * /*graph*/)
+{
+}
+
+void VectorMapRangeNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *vector_in = input("Vector");
+ ShaderInput *from_min_in = input("From_Min_FLOAT3");
+ ShaderInput *from_max_in = input("From_Max_FLOAT3");
+ ShaderInput *to_min_in = input("To_Min_FLOAT3");
+ ShaderInput *to_max_in = input("To_Max_FLOAT3");
+ ShaderInput *steps_in = input("Steps_FLOAT3");
+ ShaderOutput *vector_out = output("Vector");
+
+ int value_stack_offset = compiler.stack_assign(vector_in);
+ int from_min_stack_offset = compiler.stack_assign(from_min_in);
+ int from_max_stack_offset = compiler.stack_assign(from_max_in);
+ int to_min_stack_offset = compiler.stack_assign(to_min_in);
+ int to_max_stack_offset = compiler.stack_assign(to_max_in);
+ int steps_stack_offset = compiler.stack_assign(steps_in);
+ int result_stack_offset = compiler.stack_assign(vector_out);
+
+ compiler.add_node(
+ NODE_VECTOR_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(steps_stack_offset, use_clamp, range_type, result_stack_offset));
+}
+
+void VectorMapRangeNode::compile(OSLCompiler &compiler)
+{
+ compiler.parameter(this, "range_type");
+ compiler.parameter(this, "use_clamp");
+ compiler.add(this, "node_vector_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..a8d5bdcf157
--- /dev/null
+++ b/intern/cycles/scene/shader_nodes.h
@@ -0,0 +1,1595 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+ }
+};
+
+class PointInfoNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(PointInfoNode)
+
+ void attributes(Shader *shader, AttributeRequestSet *attributes);
+ bool has_attribute_dependency()
+ {
+ return true;
+ }
+ bool has_spatial_varying()
+ {
+ return true;
+ }
+};
+
+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 VectorMapRangeNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(VectorMapRangeNode)
+ void expand(ShaderGraph *graph);
+
+ NODE_SOCKET_API(float3, vector)
+ NODE_SOCKET_API(float3, from_min)
+ NODE_SOCKET_API(float3, from_max)
+ NODE_SOCKET_API(float3, to_min)
+ NODE_SOCKET_API(float3, to_max)
+ NODE_SOCKET_API(float3, steps)
+ NODE_SOCKET_API(NodeMapRangeType, range_type)
+ NODE_SOCKET_API(bool, use_clamp)
+};
+
+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..d121765bbdd
--- /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(3) << "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..b9021b9cbe2
--- /dev/null
+++ b/intern/cycles/session/denoising.cpp
@@ -0,0 +1,665 @@
+/*
+ * 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"
+
+#include "util/map.h"
+#include "util/system.h"
+#include "util/task.h"
+#include "util/time.h"
+
+#include <OpenImageIO/filesystem.h>
+
+CCL_NAMESPACE_BEGIN
+
+/* Utility Functions */
+
+/* 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 = 13;
+static const int INPUT_NOISY_IMAGE = 0;
+static const int INPUT_DENOISING_NORMAL = 3;
+static const int INPUT_DENOISING_ALBEDO = 6;
+static const int INPUT_MOTION = 9;
+static vector<ChannelMapping> input_channels()
+{
+ vector<ChannelMapping> map;
+ fill_mapping(map, INPUT_NOISY_IMAGE, "Combined", "RGB");
+ fill_mapping(map, INPUT_DENOISING_NORMAL, "Denoising Normal", "XYZ");
+ fill_mapping(map, INPUT_DENOISING_ALBEDO, "Denoising Albedo", "RGB");
+ fill_mapping(map, INPUT_MOTION, "Vector", "XYZW");
+ 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);
+
+ for (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);
+
+ for (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(const std::vector<string> &channelnames,
+ const std::vector<string> &neighbor_channelnames)
+{
+ vector<int> &mapping = previous_output_to_image_channel;
+
+ assert(mapping.size() == 0);
+ mapping.resize(output_to_image_channel.size(), -1);
+
+ for (int i = 0; i < output_to_image_channel.size(); i++) {
+ const string &channel = channelnames[output_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)
+ : denoiser(denoiser), device(device), frame(frame), current_layer(0), buffers(device)
+{
+}
+
+DenoiseTask::~DenoiseTask()
+{
+ free();
+}
+
+/* Denoiser Operations */
+
+bool DenoiseTask::load_input_pixels(int layer)
+{
+ /* Load center image */
+ DenoiseImageLayer &image_layer = image.layers[layer];
+
+ float *buffer_data = buffers.buffer.data();
+ image.read_pixels(image_layer, buffers.params, buffer_data);
+
+ /* Load previous image */
+ if (frame > 0 && !image.read_previous_pixels(image_layer, buffers.params, buffer_data)) {
+ error = "Failed to read neighbor frame pixels";
+ return false;
+ }
+
+ /* Copy to device */
+ buffers.buffer.copy_to_device();
+
+ return true;
+}
+
+/* Task stages */
+
+static void add_pass(vector<Pass *> &passes, PassType type, PassMode mode = PassMode::NOISY)
+{
+ Pass *pass = new Pass();
+ pass->set_type(type);
+ pass->set_mode(mode);
+
+ passes.push_back(pass);
+}
+
+bool DenoiseTask::load()
+{
+ string center_filepath = denoiser->input[frame];
+ if (!image.load(center_filepath, error)) {
+ return false;
+ }
+
+ /* Use previous frame output as input for subsequent frames. */
+ if (frame > 0 && !image.load_previous(denoiser->output[frame - 1], error)) {
+ return false;
+ }
+
+ if (image.layers.empty()) {
+ error = "No image layers found to denoise in " + center_filepath;
+ return false;
+ }
+
+ /* Enable temporal denoising for frames after the first (which will use the output from the
+ * previous frames). */
+ DenoiseParams params = denoiser->denoiser->get_params();
+ params.temporally_stable = frame > 0;
+ denoiser->denoiser->set_params(params);
+
+ /* Allocate device buffer. */
+ vector<Pass *> passes;
+ add_pass(passes, PassType::PASS_COMBINED);
+ add_pass(passes, PassType::PASS_DENOISING_ALBEDO);
+ add_pass(passes, PassType::PASS_DENOISING_NORMAL);
+ add_pass(passes, PassType::PASS_MOTION);
+ add_pass(passes, PassType::PASS_DENOISING_PREVIOUS);
+ add_pass(passes, PassType::PASS_COMBINED, PassMode::DENOISED);
+
+ BufferParams buffer_params;
+ buffer_params.width = image.width;
+ buffer_params.height = image.height;
+ buffer_params.full_x = 0;
+ buffer_params.full_y = 0;
+ buffer_params.full_width = image.width;
+ buffer_params.full_height = image.height;
+ buffer_params.update_passes(passes);
+
+ for (Pass *pass : passes) {
+ delete pass;
+ }
+
+ buffers.reset(buffer_params);
+
+ /* 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. */
+ denoiser->denoiser->denoise_buffer(buffers.params, &buffers, 1, true);
+
+ /* Copy denoised pixels from device. */
+ buffers.buffer.copy_from_device();
+
+ float *result = buffers.buffer.data(), *out = image.pixels.data();
+
+ const DenoiseImageLayer &layer = image.layers[current_layer];
+ const int *output_to_image_channel = layer.output_to_image_channel.data();
+
+ for (int y = 0; y < image.height; y++) {
+ for (int x = 0; x < image.width; x++, result += buffers.params.pass_stride) {
+ for (int j = 0; j < OUTPUT_NUM_CHANNELS; j++) {
+ int offset = buffers.params.get_pass_offset(PASS_COMBINED, PassMode::DENOISED);
+ int image_channel = output_to_image_channel[j];
+ out[image.num_channels * x + image_channel] = result[offset + j];
+ }
+ }
+ out += image.num_channels * image.width;
+ }
+
+ printf("\n");
+ }
+
+ return true;
+}
+
+bool DenoiseTask::save()
+{
+ bool ok = image.save_output(denoiser->output[frame], error);
+ free();
+ return ok;
+}
+
+void DenoiseTask::free()
+{
+ image.free();
+ buffers.buffer.free();
+}
+
+/* Denoise Image Storage */
+
+DenoiseImage::DenoiseImage()
+{
+ width = 0;
+ height = 0;
+ num_channels = 0;
+ samples = 0;
+}
+
+DenoiseImage::~DenoiseImage()
+{
+ free();
+}
+
+void DenoiseImage::close_input()
+{
+ in_previous.reset();
+}
+
+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,
+ const BufferParams &params,
+ 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 < 3; ++j) {
+ int offset = params.get_pass_offset(PASS_COMBINED);
+ int image_channel = input_to_image_channel[INPUT_NOISY_IMAGE + j];
+ input_pixels[i * params.pass_stride + offset + j] =
+ pixels[((size_t)i) * num_channels + image_channel];
+ }
+ for (int j = 0; j < 3; ++j) {
+ int offset = params.get_pass_offset(PASS_DENOISING_NORMAL);
+ int image_channel = input_to_image_channel[INPUT_DENOISING_NORMAL + j];
+ input_pixels[i * params.pass_stride + offset + j] =
+ pixels[((size_t)i) * num_channels + image_channel];
+ }
+ for (int j = 0; j < 3; ++j) {
+ int offset = params.get_pass_offset(PASS_DENOISING_ALBEDO);
+ int image_channel = input_to_image_channel[INPUT_DENOISING_ALBEDO + j];
+ input_pixels[i * params.pass_stride + offset + j] =
+ pixels[((size_t)i) * num_channels + image_channel];
+ }
+ for (int j = 0; j < 4; ++j) {
+ int offset = params.get_pass_offset(PASS_MOTION);
+ int image_channel = input_to_image_channel[INPUT_MOTION + j];
+ input_pixels[i * params.pass_stride + offset + j] =
+ pixels[((size_t)i) * num_channels + image_channel];
+ }
+ }
+}
+
+bool DenoiseImage::read_previous_pixels(const DenoiseImageLayer &layer,
+ const BufferParams &params,
+ 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_previous->read_image(TypeDesc::FLOAT, neighbor_pixels.data())) {
+ return false;
+ }
+
+ const int *output_to_image_channel = layer.previous_output_to_image_channel.data();
+
+ for (int i = 0; i < width * height; i++) {
+ for (int j = 0; j < 3; ++j) {
+ int offset = params.get_pass_offset(PASS_DENOISING_PREVIOUS);
+ int image_channel = output_to_image_channel[j];
+ input_pixels[i * params.pass_stride + offset + 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.empty()) {
+ error = "Could not find a render layer containing denoising data and motion vector passes";
+ 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_previous(const string &filepath, string &error)
+{
+ 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;
+ }
+
+ for (DenoiseImageLayer &layer : layers) {
+ if (!layer.match_channels(in_spec.channelnames, neighbor_spec.channelnames)) {
+ error = "Neighbor frame misses denoising data passes: " + filepath;
+ return false;
+ }
+ }
+
+ in_previous = 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, const DenoiseParams &params)
+{
+ /* Initialize task scheduler. */
+ TaskScheduler::init();
+
+ /* Initialize device. */
+ device = Device::create(device_info, stats, profiler);
+ device->load_kernels(KERNEL_FEATURE_DENOISING);
+
+ denoiser = Denoiser::create(device, params);
+ denoiser->load_kernels(nullptr);
+}
+
+DenoiserPipeline::~DenoiserPipeline()
+{
+ denoiser.reset();
+ delete device;
+ TaskScheduler::exit();
+}
+
+bool DenoiserPipeline::run()
+{
+ assert(input.size() == output.size());
+
+ int num_frames = output.size();
+
+ for (int frame = 0; frame < num_frames; frame++) {
+ /* Skip empty output paths. */
+ if (output[frame].empty()) {
+ continue;
+ }
+
+ /* Execute task. */
+ DenoiseTask task(device, this, frame);
+ 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
diff --git a/intern/cycles/session/denoising.h b/intern/cycles/session/denoising.h
new file mode 100644
index 00000000000..15e691f73fd
--- /dev/null
+++ b/intern/cycles/session/denoising.h
@@ -0,0 +1,184 @@
+/*
+ * 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 __DENOISING_H__
+#define __DENOISING_H__
+
+/* TODO(sergey): Make it explicit and clear when something is a denoiser, its pipeline or
+ * parameters. Currently it is an annoying mixture of terms used interchangeably. */
+
+#include "device/device.h"
+#include "integrator/denoiser.h"
+
+#include "util/string.h"
+#include "util/unique_ptr.h"
+#include "util/vector.h"
+
+#include <OpenImageIO/imageio.h>
+
+OIIO_NAMESPACE_USING
+
+CCL_NAMESPACE_BEGIN
+
+/* Denoiser pipeline */
+
+class DenoiserPipeline {
+ public:
+ DenoiserPipeline(DeviceInfo &device_info, const DenoiseParams &params);
+ ~DenoiserPipeline();
+
+ bool run();
+
+ /* Error message after running, in case of failure. */
+ string error;
+
+ /* Sequential list of frame filepaths to denoise. */
+ vector<string> input;
+ /* Sequential list of frame filepaths to write result to. Empty entries
+ * are skipped, so only a subset of the sequence can be denoised while
+ * taking into account all input frames. */
+ vector<string> output;
+
+ protected:
+ friend class DenoiseTask;
+
+ Stats stats;
+ Profiler profiler;
+ Device *device;
+ std::unique_ptr<Denoiser> denoiser;
+};
+
+/* Denoise Image Layer */
+
+struct DenoiseImageLayer {
+ string name;
+ /* All channels belonging to this DenoiseImageLayer. */
+ vector<string> channels;
+ /* Layer to image channel mapping. */
+ vector<int> layer_to_image_channel;
+
+ /* Sample amount that was used for rendering this layer. */
+ int samples;
+
+ /* Device input channel will be copied from image channel input_to_image_channel[i]. */
+ vector<int> input_to_image_channel;
+
+ /* Write i-th channel of the processing output to output_to_image_channel[i]-th channel of the
+ * file. */
+ vector<int> output_to_image_channel;
+
+ /* output_to_image_channel of the previous frame, if used. */
+ vector<int> previous_output_to_image_channel;
+
+ /* Detect whether this layer contains a full set of channels and set up the offsets accordingly.
+ */
+ bool detect_denoising_channels();
+
+ /* Map the channels of a secondary frame to the channels that are required for processing,
+ * fill neighbor_input_to_image_channel if all are present or return false if a channel are
+ * missing. */
+ bool match_channels(const std::vector<string> &channelnames,
+ const std::vector<string> &neighbor_channelnames);
+};
+
+/* Denoise Image Data */
+
+class DenoiseImage {
+ public:
+ DenoiseImage();
+ ~DenoiseImage();
+
+ /* Dimensions */
+ int width, height, num_channels;
+
+ /* Samples */
+ int samples;
+
+ /* Pixel buffer with interleaved channels. */
+ array<float> pixels;
+
+ /* Image file handles */
+ ImageSpec in_spec;
+ unique_ptr<ImageInput> in_previous;
+
+ /* Render layers */
+ vector<DenoiseImageLayer> layers;
+
+ void free();
+
+ /* Open the input image, parse its channels, open the output image and allocate the output
+ * buffer. */
+ bool load(const string &in_filepath, string &error);
+
+ /* Load neighboring frames. */
+ bool load_previous(const string &in_filepath, string &error);
+
+ /* Load subset of pixels from file buffer into input buffer, as needed for denoising
+ * on the device. Channels are reshuffled following the provided mapping. */
+ void read_pixels(const DenoiseImageLayer &layer,
+ const BufferParams &params,
+ float *input_pixels);
+ bool read_previous_pixels(const DenoiseImageLayer &layer,
+ const BufferParams &params,
+ float *input_pixels);
+
+ bool save_output(const string &out_filepath, string &error);
+
+ protected:
+ /* Parse input file channels, separate them into DenoiseImageLayers,
+ * detect DenoiseImageLayers with full channel sets,
+ * fill layers and set up the output channels and passthrough map. */
+ bool parse_channels(const ImageSpec &in_spec, string &error);
+
+ void close_input();
+};
+
+/* Denoise Task */
+
+class DenoiseTask {
+ public:
+ DenoiseTask(Device *device, DenoiserPipeline *denoiser, int frame);
+ ~DenoiseTask();
+
+ /* Task stages */
+ bool load();
+ bool exec();
+ bool save();
+ void free();
+
+ string error;
+
+ protected:
+ /* Denoiser parameters and device */
+ DenoiserPipeline *denoiser;
+ Device *device;
+
+ /* Frame number to be denoised */
+ int frame;
+
+ /* Image file data */
+ DenoiseImage image;
+ int current_layer;
+
+ RenderBuffers buffers;
+
+ /* Task handling */
+ bool load_input_pixels(int layer);
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __DENOISING_H__ */
diff --git a/intern/cycles/session/display_driver.h b/intern/cycles/session/display_driver.h
new file mode 100644
index 00000000000..c56a82436d9
--- /dev/null
+++ b/intern/cycles/session/display_driver.h
@@ -0,0 +1,147 @@
+/*
+ * 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);
+ }
+ };
+
+ virtual void next_tile_begin() = 0;
+
+ /* 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;
+
+ /* Optionally flush outstanding display commands before ending the render loop. */
+ virtual void flush(){};
+
+ 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;
+
+ /* Enforce re-creation of the graphics interop object.
+ *
+ * When this field is true then the graphics interop will be re-created no matter what the
+ * rest of the configuration is.
+ * When this field is false the graphics interop will be re-created if the PBO or buffer size
+ * did change.
+ *
+ * This allows to ensure graphics interop is re-created when there is a possibility that an
+ * underlying PBO was re-allocated but did not change its ID. */
+ bool need_recreate = 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..0a9ed37750b
--- /dev/null
+++ b/intern/cycles/session/merge.cpp
@@ -0,0 +1,621 @@
+/*
+ * 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,
+ MERGE_CHANNEL_SAMPLES,
+};
+
+struct MergeImagePass {
+ /* Full channel name. */
+ string channel_name;
+ /* Pass name. */
+ string 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 SampleCount {
+ /* Total number of samples. */
+ int total;
+ /* Buffer for actual number of samples rendered per pixel. */
+ array<float> per_pixel;
+};
+
+struct MergeImageLayer {
+ /* Layer name. */
+ string name;
+ /* Passes. */
+ vector<MergeImagePass> passes;
+ /* Sample amount that was used for rendering this layer. */
+ int samples;
+ /* Indicates if this layer has "Debug Sample Count" pass. */
+ bool has_sample_pass;
+ /* Offset of the "Debug Sample Count" pass if it exists. */
+ int sample_pass_offset;
+};
+
+/* 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 if (string_startswith(pass_name, "Debug Sample Count")) {
+ return MERGE_CHANNEL_SAMPLES;
+ }
+ 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, channelname;
+ if (parse_channel_name(
+ pass.channel_name, layername, pass.name, channelname, multiview_channels)) {
+ /* Channel part of a render layer. */
+ pass.op = parse_channel_operation(pass.name);
+ }
+ else {
+ /* Other channels are added in unnamed layer. */
+ layername = "";
+ pass.op = parse_channel_operation(pass.channel_name);
+ }
+
+ file_layers[layername].passes.push_back(pass);
+ }
+
+ /* If file contains a single unnamed layer, name it after the first layer metadata we find. */
+ if (file_layers.size() == 1 && file_layers.find("") != file_layers.end()) {
+ for (const ParamValue &attrib : in_spec.extra_attribs) {
+ const string attrib_name = attrib.name().string();
+ if (string_startswith(attrib_name, "cycles.") && string_endswith(attrib_name, ".samples")) {
+ /* Extract layer name. */
+ const size_t start = strlen("cycles.");
+ const size_t end = attrib_name.size() - strlen(".samples");
+ const string layername = attrib_name.substr(start, end - start);
+
+ /* Reinsert as named instead of unnamed layer. */
+ const MergeImageLayer layer = file_layers[""];
+ file_layers.clear();
+ file_layers[layername] = layer;
+ }
+ }
+ }
+
+ /* 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 &[name, layer] : file_layers) {
+ 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;
+ }
+
+ /* Check if the layer has "Debug Sample Count" pass. */
+ auto sample_pass_it = find_if(
+ layer.passes.begin(), layer.passes.end(), [](const MergeImagePass &pass) {
+ return pass.name == "Debug Sample Count";
+ });
+ if (sample_pass_it != layer.passes.end()) {
+ layer.has_sample_pass = true;
+ layer.sample_pass_offset = distance(layer.passes.begin(), sample_pass_it);
+ }
+ else {
+ layer.has_sample_pass = 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)
+{
+ /* 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. */
+ auto channel = find_if(
+ out_spec.channelnames.begin(),
+ out_spec.channelnames.end(),
+ [&pass](const auto &channel_name) { return pass.channel_name == channel_name; });
+
+ if (channel != out_spec.channelnames.end()) {
+ int index = distance(out_spec.channelnames.begin(), channel);
+ pass.merge_offset = index;
+
+ /* First image wins for channels that can't be averaged or summed. */
+ if (pass.op == MERGE_CHANNEL_COPY) {
+ pass.op = MERGE_CHANNEL_NOP;
+ }
+ }
+ else {
+ /* Add new channel. */
+ pass.merge_offset = out_spec.nchannels;
+
+ 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 &[layer_name, layer_samples] : layer_num_samples) {
+ string name = "cycles." + layer_name + ".samples";
+ out_spec.attribute(name, TypeDesc::STRING, to_string(layer_samples));
+
+ merge_layer_render_time(out_spec, images, layer_name, "total_time", false);
+ merge_layer_render_time(out_spec, images, layer_name, "render_time", false);
+ merge_layer_render_time(out_spec, images, layer_name, "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 = width * height;
+ pixels.resize(num_pixels * num_channels);
+}
+
+static bool merge_pixels(const vector<MergeImage> &images,
+ const ImageSpec &out_spec,
+ const unordered_map<string, SampleCount> &layer_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 (const MergeImageLayer &layer : image.layers) {
+ 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 count passes and sample metadata. Per channel since not
+ * all files are guaranteed to have the same channels. */
+ size_t sample_pass_offset = layer.sample_pass_offset;
+ const auto &samples = layer_samples.at(layer.name);
+
+ for (size_t i = 0; offset < num_pixels;
+ offset += stride, sample_pass_offset += stride, out_offset += out_stride, i++) {
+ const float total_samples = samples.per_pixel[i];
+
+ float layer_samples;
+ if (layer.has_sample_pass) {
+ layer_samples = pixels[sample_pass_offset] * layer.samples;
+ }
+ else {
+ layer_samples = layer.samples;
+ }
+
+ out_pixels[out_offset] += pixels[offset] * (1.0f * layer_samples / total_samples);
+ }
+ break;
+ }
+ case MERGE_CHANNEL_SAMPLES: {
+ const auto &samples = layer_samples.at(layer.name);
+ for (size_t i = 0; offset < num_pixels;
+ offset += stride, out_offset += out_stride, i++) {
+ out_pixels[out_offset] = 1.0f * samples.per_pixel[i] / samples.total;
+ }
+ 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;
+}
+
+static void read_layer_samples(vector<MergeImage> &images,
+ unordered_map<string, SampleCount> &layer_samples)
+{
+ for (auto &image : images) {
+ const ImageSpec &in_spec = image.in->spec();
+
+ for (auto &layer : image.layers) {
+ bool initialize = (layer_samples.count(layer.name) == 0);
+ auto &current_layer_samples = layer_samples[layer.name];
+
+ if (initialize) {
+ current_layer_samples.total = 0;
+ current_layer_samples.per_pixel.resize(in_spec.width * in_spec.height);
+ std::fill(
+ current_layer_samples.per_pixel.begin(), current_layer_samples.per_pixel.end(), 0);
+ }
+
+ if (layer.has_sample_pass) {
+ /* Load the "Debug Sample Count" pass and add the samples to the layer's sample count. */
+ array<float> sample_count_buffer;
+ sample_count_buffer.resize(in_spec.width * in_spec.height);
+ image.in->read_image(0,
+ 0,
+ layer.sample_pass_offset,
+ layer.sample_pass_offset,
+ TypeDesc::FLOAT,
+ (void *)sample_count_buffer.data());
+
+ for (size_t i = 0; i < current_layer_samples.per_pixel.size(); i++) {
+ current_layer_samples.per_pixel[i] += sample_count_buffer[i] * layer.samples;
+ }
+ }
+ else {
+ /* Use sample count from metadata if there's no "Debug Sample Count" pass. */
+ for (size_t i = 0; i < current_layer_samples.per_pixel.size(); i++) {
+ current_layer_samples.per_pixel[i] += layer.samples;
+ }
+ }
+
+ current_layer_samples.total += layer.samples;
+ }
+ }
+}
+/* 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;
+ }
+
+ /* Load and sum sample count for each render layer. */
+ unordered_map<string, SampleCount> layer_samples;
+ read_layer_samples(images, layer_samples);
+
+ /* Merge metadata and setup channels and offsets. */
+ ImageSpec out_spec;
+ merge_channels_metadata(images, out_spec);
+
+ /* Merge pixels. */
+ array<float> out_pixels;
+ if (!merge_pixels(images, out_spec, layer_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..d03063a7dda
--- /dev/null
+++ b/intern/cycles/session/session.cpp
@@ -0,0 +1,645 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+ }
+ }
+
+ path_trace_->flush_display();
+}
+
+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_start_sample(params.sample_offset);
+ 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, did_reset);
+ }
+
+ 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
+{
+ const int image_width = buffer_params_.width;
+ const int image_height = buffer_params_.height;
+
+ /* No support yet for baking with tiles. */
+ if (!params.use_auto_tile || scene->bake_manager->get_baking()) {
+ return make_int2(image_width, image_height);
+ }
+
+ const int64_t image_area = static_cast<int64_t>(image_width) * image_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);
+ const int64_t actual_tile_area = static_cast<int64_t>(tile_size) * tile_size;
+
+ if (actual_tile_area >= image_area && image_width <= TileManager::MAX_TILE_SIZE &&
+ image_height <= TileManager::MAX_TILE_SIZE) {
+ return make_int2(image_width, image_height);
+ }
+
+ 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, params.sample_offset);
+
+ /* 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);
+
+ /* Update temp directory on reset.
+ * This potentially allows to finish the existing rendering with a previously configure temporary
+ * directory in the host software and switch to a new temp directory when new render starts. */
+ tile_manager_.set_temp_dir(params.temp_dir);
+
+ /* 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 double completed = progress.get_progress();
+ if (completed == 0.0) {
+ 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 (!params.background && 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..adfd1346600
--- /dev/null
+++ b/intern/cycles/session/session.h
@@ -0,0 +1,234 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 sample_offset;
+ 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;
+
+ /* Session-specific temporary directory to store in-progress EXR files in. */
+ string temp_dir;
+
+ SessionParams()
+ {
+ headless = false;
+ background = false;
+
+ experimental = false;
+ samples = 1024;
+ sample_offset = 0;
+ 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..ab1b3b8ec36
--- /dev/null
+++ b/intern/cycles/session/tile.cpp
@@ -0,0 +1,674 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "session/session.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/time.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. */
+ const int computed_tile_size = (suggested_tile_size <= IMAGE_TILE_SIZE) ?
+ suggested_tile_size :
+ align_up(suggested_tile_size, IMAGE_TILE_SIZE);
+ return min(computed_tile_size, MAX_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;
+ }
+}
+
+void TileManager::set_temp_dir(const string &temp_dir)
+{
+ temp_dir_ = temp_dir;
+}
+
+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_join(temp_dir_,
+ "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;
+ }
+ }
+
+ const double time_start = time_dt();
+
+ DCHECK_EQ(tile_buffers.params.pass_stride, buffer_params_.pass_stride);
+
+ 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;
+
+ vector<float> pixel_storage;
+ const float *pixels = tile_buffers.buffer.data() + tile_params.window_x * pass_stride +
+ tile_params.window_y * tile_row_stride;
+
+ /* If there is an overscan used for the tile copy pixels into single continuous block of memory
+ * without any "gaps".
+ * This is a workaround for bug in OIIO (https://github.com/OpenImageIO/oiio/pull/3176).
+ * Our task reference: T93008. */
+ if (tile_params.window_x || tile_params.window_y ||
+ tile_params.window_width != tile_params.width ||
+ tile_params.window_height != tile_params.height) {
+ pixel_storage.resize(pass_stride * tile_params.window_width * tile_params.window_height);
+ float *pixels_continuous = pixel_storage.data();
+
+ const int64_t pixels_row_stride = pass_stride * tile_params.width;
+ const int64_t pixels_continuous_row_stride = pass_stride * tile_params.window_width;
+
+ for (int i = 0; i < tile_params.window_height; ++i) {
+ memcpy(pixels_continuous, pixels, sizeof(float) * pixels_continuous_row_stride);
+ pixels += pixels_row_stride;
+ pixels_continuous += pixels_continuous_row_stride;
+ }
+
+ pixels = pixel_storage.data();
+ }
+
+ 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. */
+
+ const int64_t xstride = pass_stride * sizeof(float);
+ const int64_t ystride = xstride * tile_params.window_width;
+ const int64_t zstride = ystride * tile_params.window_height;
+
+ 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;
+
+ VLOG(3) << "Tile written in " << time_dt() - time_start << " seconds.";
+
+ 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);
+ }
+
+ VLOG(3) << "Tile file size is "
+ << string_human_readable_number(path_file_size(write_state_.filename)) << " bytes.";
+
+ /* 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..80a5db543cd
--- /dev/null
+++ b/intern/cycles/session/tile.h
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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);
+
+ void set_temp_dir(const string &temp_dir);
+
+ 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;
+
+ /* Maximum supported tile size.
+ * Needs to be safe from allocation on a GPU point of view: the display driver needs to be able
+ * to allocate texture with the side size of this value.
+ * Use conservative value which is safe for most of OpenGL drivers and GPUs. */
+ static const int MAX_TILE_SIZE = 8192;
+
+ 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();
+
+ string temp_dir_;
+
+ /* 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..c6c992008a0 100644
--- a/intern/cycles/test/CMakeLists.txt
+++ b/intern/cycles/test/CMakeLists.txt
@@ -20,31 +20,24 @@ 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}
)
include_directories(${INC})
-cycles_link_directories()
-
set(SRC
integrator_adaptive_sampling_test.cpp
integrator_render_scheduler_test.cpp
@@ -59,17 +52,21 @@ set(SRC
util_transform_test.cpp
)
-if(CXX_HAS_AVX)
- list(APPEND SRC
- util_avxf_avx_test.cpp
- )
- set_source_files_properties(util_avxf_avx_test.cpp PROPERTIES COMPILE_FLAGS "${CYCLES_AVX_KERNEL_FLAGS}")
-endif()
-if(CXX_HAS_AVX2)
- list(APPEND SRC
- util_avxf_avx2_test.cpp
- )
- set_source_files_properties(util_avxf_avx2_test.cpp PROPERTIES COMPILE_FLAGS "${CYCLES_AVX2_KERNEL_FLAGS}")
+# Disable AVX tests on macOS. Rosetta has problems running them, and other
+# platforms should be enough to verify AVX operations are implemented correctly.
+if(NOT APPLE)
+ if(CXX_HAS_AVX)
+ list(APPEND SRC
+ util_avxf_avx_test.cpp
+ )
+ set_source_files_properties(util_avxf_avx_test.cpp PROPERTIES COMPILE_FLAGS "${CYCLES_AVX_KERNEL_FLAGS}")
+ endif()
+ if(CXX_HAS_AVX2)
+ list(APPEND SRC
+ util_avxf_avx2_test.cpp
+ )
+ set_source_files_properties(util_avxf_avx2_test.cpp PROPERTIES COMPILE_FLAGS "${CYCLES_AVX2_KERNEL_FLAGS}")
+ endif()
endif()
if(WITH_GTESTS)
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..1d078a2d19a 100644
--- a/intern/cycles/test/integrator_tile_test.cpp
+++ b/intern/cycles/test/integrator_tile_test.cpp
@@ -17,30 +17,34 @@
#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(false, make_int2(1920, 1080), 1, 1, 1.0f), TileSize(1, 1, 1));
+ EXPECT_EQ(tile_calculate_best_size(false, 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(false, 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(false, 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(false, make_int2(32, 32), 262144, 131072, 1.0f),
+ TileSize(1, 1, 512));
+ EXPECT_EQ(tile_calculate_best_size(false, make_int2(32, 32), 1048576, 131072, 1.0f),
+ TileSize(1, 1, 1024));
+ EXPECT_EQ(tile_calculate_best_size(false, 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(false, 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..390d3a2d5f8 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 "scene/scene.h"
+#include "scene/shader_graph.h"
+#include "scene/shader_nodes.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 "util/array.h"
+#include "util/log.h"
+#include "util/stats.h"
+#include "util/string.h"
+#include "util/vector.h"
using testing::_;
using testing::AnyNumber;
@@ -179,7 +179,7 @@ class RenderGraph : public testing::Test {
virtual void SetUp()
{
util_logging_start();
- util_logging_verbosity_set(1);
+ util_logging_verbosity_set(3);
device_cpu = Device::create(device_info, stats, profiler);
scene = new Scene(scene_params, device_cpu);
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..344be4b3a2c 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
@@ -32,9 +32,13 @@ static bool validate_cpu_capabilities()
#endif
}
-#define VALIDATECPU \
+#define INIT_AVX_TEST \
if (!validate_cpu_capabilities()) \
- return;
+ return; \
+\
+ const avxf avxf_a(0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f); \
+ const avxf avxf_b(1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f); \
+ const avxf avxf_c(1.1f, 2.2f, 3.3f, 4.4f, 5.5f, 6.6f, 7.7f, 8.8f);
#define compare_vector_scalar(a, b) \
for (size_t index = 0; index < a.size; index++) \
@@ -49,21 +53,18 @@ static bool validate_cpu_capabilities()
EXPECT_NEAR(a[index], b[index], abserror);
#define basic_test_vv(a, b, op) \
- VALIDATECPU \
+ INIT_AVX_TEST \
avxf c = a op b; \
for (size_t i = 0; i < a.size; i++) \
EXPECT_FLOAT_EQ(c[i], a[i] op b[i]);
/* vector op float tests */
#define basic_test_vf(a, b, op) \
- VALIDATECPU \
+ INIT_AVX_TEST \
avxf c = a op b; \
for (size_t i = 0; i < a.size; i++) \
EXPECT_FLOAT_EQ(c[i], a[i] op b);
-static const avxf avxf_a(0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f);
-static const avxf avxf_b(1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f);
-static const avxf avxf_c(1.1f, 2.2f, 3.3f, 4.4f, 5.5f, 6.6f, 7.7f, 8.8f);
static const float float_b = 1.5f;
TEST(TEST_CATEGORY_NAME, avxf_add_vv){basic_test_vv(avxf_a, avxf_b, +)} TEST(TEST_CATEGORY_NAME,
@@ -78,7 +79,7 @@ TEST(TEST_CATEGORY_NAME, avxf_add_vv){basic_test_vv(avxf_a, avxf_b, +)} TEST(TES
TEST(TEST_CATEGORY_NAME, avxf_ctor)
{
- VALIDATECPU
+ INIT_AVX_TEST
compare_vector_scalar(avxf(7.0f, 6.0f, 5.0f, 4.0f, 3.0f, 2.0f, 1.0f, 0.0f),
static_cast<float>(index));
compare_vector_scalar(avxf(1.0f), 1.0f);
@@ -91,28 +92,28 @@ TEST(TEST_CATEGORY_NAME, avxf_ctor)
TEST(TEST_CATEGORY_NAME, avxf_sqrt)
{
- VALIDATECPU
+ INIT_AVX_TEST
compare_vector_vector(mm256_sqrt(avxf(1.0f, 4.0f, 9.0f, 16.0f, 25.0f, 36.0f, 49.0f, 64.0f)),
avxf(1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f));
}
TEST(TEST_CATEGORY_NAME, avxf_min_max)
{
- VALIDATECPU
+ INIT_AVX_TEST
compare_vector_vector(min(avxf_a, avxf_b), avxf_a);
compare_vector_vector(max(avxf_a, avxf_b), avxf_b);
}
TEST(TEST_CATEGORY_NAME, avxf_set_sign)
{
- VALIDATECPU
+ INIT_AVX_TEST
avxf res = set_sign_bit<1, 0, 0, 0, 0, 0, 0, 0>(avxf_a);
compare_vector_vector(res, avxf(0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, -0.8f));
}
TEST(TEST_CATEGORY_NAME, avxf_msub)
{
- VALIDATECPU
+ INIT_AVX_TEST
avxf res = msub(avxf_a, avxf_b, avxf_c);
avxf exp = avxf((avxf_a[7] * avxf_b[7]) - avxf_c[7],
(avxf_a[6] * avxf_b[6]) - avxf_c[6],
@@ -127,7 +128,7 @@ TEST(TEST_CATEGORY_NAME, avxf_msub)
TEST(TEST_CATEGORY_NAME, avxf_madd)
{
- VALIDATECPU
+ INIT_AVX_TEST
avxf res = madd(avxf_a, avxf_b, avxf_c);
avxf exp = avxf((avxf_a[7] * avxf_b[7]) + avxf_c[7],
(avxf_a[6] * avxf_b[6]) + avxf_c[6],
@@ -142,7 +143,7 @@ TEST(TEST_CATEGORY_NAME, avxf_madd)
TEST(TEST_CATEGORY_NAME, avxf_nmadd)
{
- VALIDATECPU
+ INIT_AVX_TEST
avxf res = nmadd(avxf_a, avxf_b, avxf_c);
avxf exp = avxf(avxf_c[7] - (avxf_a[7] * avxf_b[7]),
avxf_c[6] - (avxf_a[6] * avxf_b[6]),
@@ -157,7 +158,7 @@ TEST(TEST_CATEGORY_NAME, avxf_nmadd)
TEST(TEST_CATEGORY_NAME, avxf_compare)
{
- VALIDATECPU
+ INIT_AVX_TEST
avxf a(0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f);
avxf b(7.0f, 6.0f, 5.0f, 4.0f, 3.0f, 2.0f, 1.0f, 0.0f);
avxb res = a <= b;
@@ -176,28 +177,28 @@ TEST(TEST_CATEGORY_NAME, avxf_compare)
TEST(TEST_CATEGORY_NAME, avxf_permute)
{
- VALIDATECPU
+ INIT_AVX_TEST
avxf res = permute<3, 0, 1, 7, 6, 5, 2, 4>(avxf_b);
compare_vector_vector(res, avxf(4.0f, 6.0f, 3.0f, 2.0f, 1.0f, 7.0f, 8.0f, 5.0f));
}
TEST(TEST_CATEGORY_NAME, avxf_blend)
{
- VALIDATECPU
+ INIT_AVX_TEST
avxf res = blend<0, 0, 1, 0, 1, 0, 1, 0>(avxf_a, avxf_b);
compare_vector_vector(res, avxf(0.1f, 0.2f, 3.0f, 0.4f, 5.0f, 0.6f, 7.0f, 0.8f));
}
TEST(TEST_CATEGORY_NAME, avxf_shuffle)
{
- VALIDATECPU
+ INIT_AVX_TEST
avxf res = shuffle<0, 1, 2, 3, 1, 3, 2, 0>(avxf_a);
compare_vector_vector(res, avxf(0.4f, 0.2f, 0.1f, 0.3f, 0.5f, 0.6f, 0.7f, 0.8f));
}
TEST(TEST_CATEGORY_NAME, avxf_cross)
{
- VALIDATECPU
+ INIT_AVX_TEST
avxf res = cross(avxf_b, avxf_c);
compare_vector_vector_near(res,
avxf(0.0f,
@@ -213,7 +214,7 @@ TEST(TEST_CATEGORY_NAME, avxf_cross)
TEST(TEST_CATEGORY_NAME, avxf_dot3)
{
- VALIDATECPU
+ INIT_AVX_TEST
float den, den2;
dot3(avxf_a, avxf_b, den, den2);
EXPECT_FLOAT_EQ(den, 14.9f);
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..a26934c0ace 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,124 +48,114 @@ set(LIB
if(WITH_CYCLES_STANDALONE)
if(WITH_CYCLES_STANDALONE_GUI)
list(APPEND SRC
- util_view.cpp
+ view.cpp
)
endif()
endif()
-if(CYCLES_STANDALONE_REPOSITORY)
- list(APPEND INC_SYS
- ../../third_party/numaapi/include
- )
-else()
- list(APPEND INC_SYS
- ../../numaapi/include
- )
-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..1c5e3e8d4ec
--- /dev/null
+++ b/intern/cycles/util/array.h
@@ -0,0 +1,322 @@
+/*
+ * 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) {
+ mem_copy(data_, from.data_, from.datasize_);
+ }
+ datasize_ = from.datasize_;
+ capacity_ = datasize_;
+ }
+ }
+
+ array &operator=(const array &from)
+ {
+ if (this != &from) {
+ resize(from.size());
+ if (datasize_ > 0) {
+ mem_copy(data_, from.data_, datasize_);
+ }
+ }
+
+ return *this;
+ }
+
+ array &operator=(const vector<T> &from)
+ {
+ resize(from.size());
+
+ if (from.size() > 0 && datasize_ > 0) {
+ mem_copy(data_, from.data(), datasize_);
+ }
+
+ 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) {
+ mem_copy(newdata, data_, ((datasize_ < newsize) ? datasize_ : newsize));
+ 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) {
+ mem_copy(newdata, data_, ((datasize_ < newcapacity) ? datasize_ : newcapacity));
+ 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());
+ mem_copy(data_ + old_size, from.data(), 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);
+ }
+ }
+
+ inline void mem_copy(T *mem_to, const T *mem_from, const size_t N)
+ {
+ memcpy((void *)mem_to, mem_from, sizeof(T) * N);
+ }
+
+ T *data_;
+ size_t datasize_;
+ size_t capacity_;
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_ARRAY_H__ */
diff --git a/intern/cycles/util/atomic.h b/intern/cycles/util/atomic.h
new file mode 100644
index 00000000000..afc3fd019df
--- /dev/null
+++ b/intern/cycles/util/atomic.h
@@ -0,0 +1,124 @@
+/*
+ * 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_ATOMIC_H__
+#define __UTIL_ATOMIC_H__
+
+#ifndef __KERNEL_GPU__
+
+/* Using atomic ops header from Blender. */
+# include "atomic_ops.h"
+
+# define atomic_add_and_fetch_float(p, x) atomic_add_and_fetch_fl((p), (x))
+# define atomic_compare_and_swap_float(p, old_val, new_val) \
+ atomic_cas_float((p), (old_val), (new_val))
+
+# define atomic_fetch_and_inc_uint32(p) atomic_fetch_and_add_uint32((p), 1)
+# define atomic_fetch_and_dec_uint32(p) atomic_fetch_and_add_uint32((p), -1)
+
+# define CCL_LOCAL_MEM_FENCE 0
+# define ccl_barrier(flags) ((void)0)
+
+#else /* __KERNEL_GPU__ */
+
+# if defined(__KERNEL_CUDA__) || defined(__KERNEL_HIP__)
+
+# define atomic_add_and_fetch_float(p, x) (atomicAdd((float *)(p), (float)(x)) + (float)(x))
+
+# define atomic_fetch_and_add_uint32(p, x) atomicAdd((unsigned int *)(p), (unsigned int)(x))
+# define atomic_fetch_and_sub_uint32(p, x) atomicSub((unsigned int *)(p), (unsigned int)(x))
+# define atomic_fetch_and_inc_uint32(p) atomic_fetch_and_add_uint32((p), 1)
+# define atomic_fetch_and_dec_uint32(p) atomic_fetch_and_sub_uint32((p), 1)
+# define atomic_fetch_and_or_uint32(p, x) atomicOr((unsigned int *)(p), (unsigned int)(x))
+
+ccl_device_inline float atomic_compare_and_swap_float(volatile float *dest,
+ const float old_val,
+ const float new_val)
+{
+ union {
+ unsigned int int_value;
+ float float_value;
+ } new_value, prev_value, result;
+ prev_value.float_value = old_val;
+ new_value.float_value = new_val;
+ result.int_value = atomicCAS((unsigned int *)dest, prev_value.int_value, new_value.int_value);
+ return result.float_value;
+}
+
+# define CCL_LOCAL_MEM_FENCE
+# define ccl_barrier(flags) __syncthreads()
+
+# endif /* __KERNEL_CUDA__ */
+
+# ifdef __KERNEL_METAL__
+
+// global address space versions
+ccl_device_inline float atomic_add_and_fetch_float(volatile ccl_global float *_source,
+ const float operand)
+{
+ volatile ccl_global atomic_int *source = (ccl_global atomic_int *)_source;
+ union {
+ int int_value;
+ float float_value;
+ } new_value, prev_value;
+ prev_value.int_value = atomic_load_explicit(source, memory_order_relaxed);
+ do {
+ new_value.float_value = prev_value.float_value + operand;
+ } while (!atomic_compare_exchange_weak_explicit(source,
+ &prev_value.int_value,
+ new_value.int_value,
+ memory_order_relaxed,
+ memory_order_relaxed));
+
+ return new_value.float_value;
+}
+
+# define atomic_fetch_and_add_uint32(p, x) \
+ atomic_fetch_add_explicit((device atomic_uint *)p, x, memory_order_relaxed)
+# define atomic_fetch_and_sub_uint32(p, x) \
+ atomic_fetch_sub_explicit((device atomic_uint *)p, x, memory_order_relaxed)
+# define atomic_fetch_and_inc_uint32(p) \
+ atomic_fetch_add_explicit((device atomic_uint *)p, 1, memory_order_relaxed)
+# define atomic_fetch_and_dec_uint32(p) \
+ atomic_fetch_sub_explicit((device atomic_uint *)p, 1, memory_order_relaxed)
+# define atomic_fetch_and_or_uint32(p, x) \
+ atomic_fetch_or_explicit((device atomic_uint *)p, x, memory_order_relaxed)
+
+ccl_device_inline float atomic_compare_and_swap_float(volatile ccl_global float *dest,
+ const float old_val,
+ const float new_val)
+{
+ int prev_value;
+ prev_value = __float_as_int(old_val);
+ atomic_compare_exchange_weak_explicit((ccl_global atomic_int *)dest,
+ &prev_value,
+ __float_as_int(new_val),
+ memory_order_relaxed,
+ memory_order_relaxed);
+ return __int_as_float(prev_value);
+}
+
+# define atomic_store(p, x) atomic_store_explicit(p, x, memory_order_relaxed)
+# define atomic_fetch(p) atomic_load_explicit(p, memory_order_relaxed)
+
+# define CCL_LOCAL_MEM_FENCE mem_flags::mem_threadgroup
+# define ccl_barrier(flags) threadgroup_barrier(flags)
+
+# endif /* __KERNEL_METAL__ */
+
+#endif /* __KERNEL_GPU__ */
+
+#endif /* __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..717e55a2c9a
--- /dev/null
+++ b/intern/cycles/util/debug.cpp
@@ -0,0 +1,114 @@
+/*
+ * 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();
+}
+
+DebugFlags::Metal::Metal() : 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;
+}
+
+void DebugFlags::Metal::reset()
+{
+ if (getenv("CYCLES_METAL_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();
+ metal.reset();
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/util/debug.h b/intern/cycles/util/debug.h
new file mode 100644
index 00000000000..1e431fde68a
--- /dev/null
+++ b/intern/cycles/util/debug.h
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+ };
+
+ /* Descriptor of Metal feature-set to be used. */
+ struct Metal {
+ Metal();
+
+ /* Reset flags to their defaults. */
+ void reset();
+
+ /* Whether adaptive feature based runtime compile is enabled or not.*/
+ bool adaptive_compile;
+ };
+
+ /* 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;
+
+ /* Requested Metal flags. */
+ Metal metal;
+
+ 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();
+}
+
+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..a2e8d83adb7
--- /dev/null
+++ b/intern/cycles/util/defines.h
@@ -0,0 +1,153 @@
+
+/*
+ * 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_device_inline_method __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_device_inline_method __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_inline_constant inline constexpr
+# 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..555f17259bd
--- /dev/null
+++ b/intern/cycles/util/half.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.
+ */
+
+#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 */
+
+#if defined(__KERNEL_METAL__)
+
+ccl_device_inline float half_to_float(half h_in)
+{
+ float f;
+ union {
+ half h;
+ uint16_t s;
+ } val;
+ val.h = h_in;
+
+ *((ccl_private int *)&f) = ((val.s & 0x8000) << 16) | (((val.s & 0x7c00) + 0x1C000) << 13) |
+ ((val.s & 0x03FF) << 13);
+
+ return f;
+}
+
+#else
+
+/* 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;
+};
+#endif
+
+/* 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_METAL__)
+ return half(f);
+#elif 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_METAL__)
+ return half_to_float(h);
+#elif 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_METAL__)
+ return half(f);
+#elif 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..e924d660407
--- /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 version of the
+// allocator here (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 is 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..605a19aaef0
--- /dev/null
+++ b/intern/cycles/util/math.h
@@ -0,0 +1,934 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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
+
+#if !defined(__KERNEL_METAL__)
+# include <float.h>
+# include <math.h>
+# include <stdio.h>
+#endif /* !defined(__KERNEL_METAL__) */
+
+#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));
+}
+
+#if !defined(__KERNEL_METAL__)
+/* 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
+}
+#endif /* !defined(__KERNEL_METAL__) */
+
+#if defined(__KERNEL_METAL__)
+# define isnan_safe(v) isnan(v)
+# define isfinite_safe(v) isfinite(v)
+#else
+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);
+}
+#endif
+
+ccl_device_inline float ensure_finite(float v)
+{
+ return isfinite_safe(v) ? v : 0.0f;
+}
+
+#if !defined(__KERNEL_METAL__)
+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;
+}
+
+#endif /* !defined(__KERNEL_METAL__) */
+
+#if defined(__KERNEL_CUDA__)
+ccl_device_inline float saturatef(float a)
+{
+ return __saturatef(a);
+}
+#elif !defined(__KERNEL_METAL__)
+ccl_device_inline float saturatef(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/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
+
+#if !defined(__KERNEL_METAL__)
+/* 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);
+}
+
+#endif /* __KERNEL_METAL__ */
+
+/* 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)
+{
+#if defined(__KERNEL_METAL__)
+ return (f > 0.0f) ? rsqrt(f) : 0.0f;
+#else
+ return (f > 0.0f) ? 1.0f / sqrtf(f) : 0.0f;
+#endif
+}
+
+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));
+}
+
+#ifdef __KERNEL_METAL__
+ccl_device_inline float lgammaf(float x)
+{
+ /* Nemes, Gergő (2010), "New asymptotic expansion for the Gamma function", Archiv der Mathematik
+ */
+ const float _1_180 = 1.0f / 180.0f;
+ const float log2pi = 1.83787706641f;
+ const float logx = log(x);
+ return (log2pi - logx +
+ x * (logx * 2.0f + log(x * sinh(1.0f / x) + (_1_180 / pow(x, 6.0f))) - 2.0f)) *
+ 0.5f;
+}
+#endif
+
+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);
+}
+
+#if !defined(__KERNEL_GPU__)
+# if defined(__GNUC__)
+# define popcount(x) __builtin_popcount(x)
+# else
+ccl_device_inline uint popcount(uint x)
+{
+ /* TODO(Stefan): pop-count intrinsic for Windows with fallback for older CPUs. */
+ uint i = x & 0xaaaaaaaa;
+ i = i - ((i >> 1) & 0x55555555);
+ i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
+ i = (((i + (i >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24;
+ return i & 1;
+}
+# endif
+#elif !defined(__KERNEL_METAL__)
+# define popcount(x) __popc(x)
+#endif
+
+ccl_device_inline uint count_leading_zeros(uint x)
+{
+#if defined(__KERNEL_CUDA__) || defined(__KERNEL_OPTIX__) || defined(__KERNEL_HIP__)
+ return __clz(x);
+#elif defined(__KERNEL_METAL__)
+ 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);
+#elif defined(__KERNEL_METAL__)
+ return ctz(x);
+#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);
+#elif defined(__KERNEL_METAL__)
+ return (x != 0) ? ctz(x) + 1 : 0;
+#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 bool 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 defined(__KERNEL_METAL__)
+ return reverse_bits(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/math_fast.h b/intern/cycles/util/math_fast.h
new file mode 100644
index 00000000000..e2a33b1c26c
--- /dev/null
+++ b/intern/cycles/util/math_fast.h
@@ -0,0 +1,652 @@
+/*
+ * Adapted from OpenImageIO library with this license:
+ *
+ * Copyright 2008-2014 Larry Gritz and the other authors and contributors.
+ * 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 the software's owners 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.
+ *
+ * (This is the Modified BSD License)
+ *
+ * A few bits here are based upon code from NVIDIA that was also released
+ * under the same modified BSD license, and marked as:
+ * Copyright 2004 NVIDIA Corporation. All Rights Reserved.
+ *
+ * Some parts of this file were first open-sourced in Open Shading Language,
+ * then later moved here. The original copyright notice was:
+ * Copyright (c) 2009-2014 Sony Pictures Imageworks Inc., et al.
+ *
+ * Many of the math functions were copied from or inspired by other
+ * public domain sources or open source packages with compatible licenses.
+ * The individual functions give references were applicable.
+ */
+
+#ifndef __UTIL_FAST_MATH__
+#define __UTIL_FAST_MATH__
+
+CCL_NAMESPACE_BEGIN
+
+ccl_device_inline float madd(const float a, const float b, const float c)
+{
+ /* NOTE: In the future we may want to explicitly ask for a fused
+ * multiply-add in a specialized version for float.
+ *
+ * NOTE: GCC/ICC will turn this (for float) into a FMA unless
+ * explicitly asked not to, clang seems to leave the code alone.
+ */
+ return a * b + c;
+}
+
+ccl_device_inline float4 madd4(const float4 a, const float4 b, const float4 c)
+{
+ return a * b + c;
+}
+
+/*
+ * FAST & APPROXIMATE MATH
+ *
+ * The functions named "fast_*" provide a set of replacements to libm that
+ * are much faster at the expense of some accuracy and robust handling of
+ * extreme values. One design goal for these approximation was to avoid
+ * branches as much as possible and operate on single precision values only
+ * so that SIMD versions should be straightforward ports We also try to
+ * implement "safe" semantics (ie: clamp to valid range where possible)
+ * natively since wrapping these inline calls in another layer would be
+ * wasteful.
+ *
+ * Some functions are fast_safe_*, which is both a faster approximation as
+ * well as clamped input domain to ensure no NaN, Inf, or divide by zero.
+ */
+
+/* Round to nearest integer, returning as an int. */
+ccl_device_inline int fast_rint(float x)
+{
+ /* used by sin/cos/tan range reduction. */
+#ifdef __KERNEL_SSE4__
+ /* Single `roundps` instruction on SSE4.1+ (for gcc/clang at least). */
+ return float_to_int(rintf(x));
+#else
+ /* emulate rounding by adding/subtracting 0.5. */
+ return float_to_int(x + copysignf(0.5f, x));
+#endif
+}
+
+ccl_device float fast_sinf(float x)
+{
+ /* Very accurate argument reduction from SLEEF,
+ * starts failing around x=262000
+ *
+ * Results on: [-2pi,2pi].
+ *
+ * Examined 2173837240 values of sin: 0.00662760244 avg ulp diff, 2 max ulp,
+ * 1.19209e-07 max error
+ */
+ int q = fast_rint(x * M_1_PI_F);
+ float qf = (float)q;
+ x = madd(qf, -0.78515625f * 4, x);
+ x = madd(qf, -0.00024187564849853515625f * 4, x);
+ x = madd(qf, -3.7747668102383613586e-08f * 4, x);
+ x = madd(qf, -1.2816720341285448015e-12f * 4, x);
+ x = M_PI_2_F - (M_PI_2_F - x); /* Crush denormals */
+ float s = x * x;
+ if ((q & 1) != 0)
+ x = -x;
+ /* This polynomial approximation has very low error on [-pi/2,+pi/2]
+ * 1.19209e-07 max error in total over [-2pi,+2pi]. */
+ float u = 2.6083159809786593541503e-06f;
+ u = madd(u, s, -0.0001981069071916863322258f);
+ u = madd(u, s, +0.00833307858556509017944336f);
+ u = madd(u, s, -0.166666597127914428710938f);
+ u = madd(s, u * x, x);
+ /* For large x, the argument reduction can fail and the polynomial can be
+ * evaluated with arguments outside the valid internal. Just clamp the bad
+ * values away (setting to 0.0f means no branches need to be generated). */
+ if (fabsf(u) > 1.0f) {
+ u = 0.0f;
+ }
+ return u;
+}
+
+ccl_device float fast_cosf(float x)
+{
+ /* Same argument reduction as fast_sinf(). */
+ int q = fast_rint(x * M_1_PI_F);
+ float qf = (float)q;
+ x = madd(qf, -0.78515625f * 4, x);
+ x = madd(qf, -0.00024187564849853515625f * 4, x);
+ x = madd(qf, -3.7747668102383613586e-08f * 4, x);
+ x = madd(qf, -1.2816720341285448015e-12f * 4, x);
+ x = M_PI_2_F - (M_PI_2_F - x); /* Crush denormals. */
+ float s = x * x;
+ /* Polynomial from SLEEF's sincosf, max error is
+ * 4.33127e-07 over [-2pi,2pi] (98% of values are "exact"). */
+ float u = -2.71811842367242206819355e-07f;
+ u = madd(u, s, +2.47990446951007470488548e-05f);
+ u = madd(u, s, -0.00138888787478208541870117f);
+ u = madd(u, s, +0.0416666641831398010253906f);
+ u = madd(u, s, -0.5f);
+ u = madd(u, s, +1.0f);
+ if ((q & 1) != 0) {
+ u = -u;
+ }
+ if (fabsf(u) > 1.0f) {
+ u = 0.0f;
+ }
+ return u;
+}
+
+ccl_device void fast_sincosf(float x, ccl_private float *sine, ccl_private float *cosine)
+{
+ /* Same argument reduction as fast_sin. */
+ int q = fast_rint(x * M_1_PI_F);
+ float qf = (float)q;
+ x = madd(qf, -0.78515625f * 4, x);
+ x = madd(qf, -0.00024187564849853515625f * 4, x);
+ x = madd(qf, -3.7747668102383613586e-08f * 4, x);
+ x = madd(qf, -1.2816720341285448015e-12f * 4, x);
+ x = M_PI_2_F - (M_PI_2_F - x); // crush denormals
+ float s = x * x;
+ /* NOTE: same exact polynomials as fast_sinf() and fast_cosf() above. */
+ if ((q & 1) != 0) {
+ x = -x;
+ }
+ float su = 2.6083159809786593541503e-06f;
+ su = madd(su, s, -0.0001981069071916863322258f);
+ su = madd(su, s, +0.00833307858556509017944336f);
+ su = madd(su, s, -0.166666597127914428710938f);
+ su = madd(s, su * x, x);
+ float cu = -2.71811842367242206819355e-07f;
+ cu = madd(cu, s, +2.47990446951007470488548e-05f);
+ cu = madd(cu, s, -0.00138888787478208541870117f);
+ cu = madd(cu, s, +0.0416666641831398010253906f);
+ cu = madd(cu, s, -0.5f);
+ cu = madd(cu, s, +1.0f);
+ if ((q & 1) != 0) {
+ cu = -cu;
+ }
+ if (fabsf(su) > 1.0f) {
+ su = 0.0f;
+ }
+ if (fabsf(cu) > 1.0f) {
+ cu = 0.0f;
+ }
+ *sine = su;
+ *cosine = cu;
+}
+
+/* NOTE: this approximation is only valid on [-8192.0,+8192.0], it starts
+ * becoming really poor outside of this range because the reciprocal amplifies
+ * errors.
+ */
+ccl_device float fast_tanf(float x)
+{
+ /* Derived from SLEEF implementation.
+ *
+ * Note that we cannot apply the "denormal crush" trick everywhere because
+ * we sometimes need to take the reciprocal of the polynomial
+ */
+ int q = fast_rint(x * 2.0f * M_1_PI_F);
+ float qf = (float)q;
+ x = madd(qf, -0.78515625f * 2, x);
+ x = madd(qf, -0.00024187564849853515625f * 2, x);
+ x = madd(qf, -3.7747668102383613586e-08f * 2, x);
+ x = madd(qf, -1.2816720341285448015e-12f * 2, x);
+ if ((q & 1) == 0) {
+ /* Crush denormals (only if we aren't inverting the result later). */
+ x = M_PI_4_F - (M_PI_4_F - x);
+ }
+ float s = x * x;
+ float u = 0.00927245803177356719970703f;
+ u = madd(u, s, 0.00331984995864331722259521f);
+ u = madd(u, s, 0.0242998078465461730957031f);
+ u = madd(u, s, 0.0534495301544666290283203f);
+ u = madd(u, s, 0.133383005857467651367188f);
+ u = madd(u, s, 0.333331853151321411132812f);
+ u = madd(s, u * x, x);
+ if ((q & 1) != 0) {
+ u = -1.0f / u;
+ }
+ return u;
+}
+
+/* Fast, approximate sin(x*M_PI) with maximum absolute error of 0.000918954611.
+ *
+ * Adapted from http://devmaster.net/posts/9648/fast-and-accurate-sine-cosine#comment-76773
+ */
+ccl_device float fast_sinpif(float x)
+{
+ /* Fast trick to strip the integral part off, so our domain is [-1, 1]. */
+ const float z = x - ((x + 25165824.0f) - 25165824.0f);
+ const float y = z - z * fabsf(z);
+ const float Q = 3.10396624f;
+ const float P = 3.584135056f; /* P = 16-4*Q */
+ return y * (Q + P * fabsf(y));
+
+ /* The original article used inferior constants for Q and P and
+ * so had max error 1.091e-3.
+ *
+ * The optimal value for Q was determined by exhaustive search, minimizing
+ * the absolute numerical error relative to float(std::sin(double(phi*M_PI)))
+ * over the interval [0,2] (which is where most of the invocations happen).
+ *
+ * The basic idea of this approximation starts with the coarse approximation:
+ * sin(pi*x) ~= f(x) = 4 * (x - x * abs(x))
+ *
+ * This approximation always _over_ estimates the target. On the other hand,
+ * the curve:
+ * sin(pi*x) ~= f(x) * abs(f(x)) / 4
+ *
+ * always lies _under_ the target. Thus we can simply numerically search for
+ * the optimal constant to LERP these curves into a more precise
+ * approximation.
+ *
+ * After folding the constants together and simplifying the resulting math,
+ * we end up with the compact implementation above.
+ *
+ * NOTE: this function actually computes sin(x * pi) which avoids one or two
+ * mults in many cases and guarantees exact values at integer periods.
+ */
+}
+
+/* Fast approximate cos(x*M_PI) with ~0.1% absolute error. */
+ccl_device_inline float fast_cospif(float x)
+{
+ return fast_sinpif(x + 0.5f);
+}
+
+ccl_device float fast_acosf(float x)
+{
+ const float f = fabsf(x);
+ /* clamp and crush denormals. */
+ const float m = (f < 1.0f) ? 1.0f - (1.0f - f) : 1.0f;
+ /* Based on http://www.pouet.net/topic.php?which=9132&page=2
+ * 85% accurate (ulp 0)
+ * Examined 2130706434 values of acos:
+ * 15.2000597 avg ulp diff, 4492 max ulp, 4.51803e-05 max error // without "denormal crush"
+ * Examined 2130706434 values of acos:
+ * 15.2007108 avg ulp diff, 4492 max ulp, 4.51803e-05 max error // with "denormal crush"
+ */
+ const float a = sqrtf(1.0f - m) *
+ (1.5707963267f + m * (-0.213300989f + m * (0.077980478f + m * -0.02164095f)));
+ return x < 0 ? M_PI_F - a : a;
+}
+
+ccl_device float fast_asinf(float x)
+{
+ /* Based on acosf approximation above.
+ * Max error is 4.51133e-05 (ulps are higher because we are consistently off
+ * by a little amount).
+ */
+ const float f = fabsf(x);
+ /* Clamp and crush denormals. */
+ const float m = (f < 1.0f) ? 1.0f - (1.0f - f) : 1.0f;
+ const float a = M_PI_2_F -
+ sqrtf(1.0f - m) * (1.5707963267f +
+ m * (-0.213300989f + m * (0.077980478f + m * -0.02164095f)));
+ return copysignf(a, x);
+}
+
+ccl_device float fast_atanf(float x)
+{
+ const float a = fabsf(x);
+ const float k = a > 1.0f ? 1 / a : a;
+ const float s = 1.0f - (1.0f - k); /* Crush denormals. */
+ const float t = s * s;
+ /* http://mathforum.org/library/drmath/view/62672.html
+ * Examined 4278190080 values of atan:
+ * 2.36864877 avg ulp diff, 302 max ulp, 6.55651e-06 max error // (with denormals)
+ * Examined 4278190080 values of atan:
+ * 171160502 avg ulp diff, 855638016 max ulp, 6.55651e-06 max error // (crush denormals)
+ */
+ float r = s * madd(0.43157974f, t, 1.0f) / madd(madd(0.05831938f, t, 0.76443945f), t, 1.0f);
+ if (a > 1.0f) {
+ r = M_PI_2_F - r;
+ }
+ return copysignf(r, x);
+}
+
+ccl_device float fast_atan2f(float y, float x)
+{
+ /* Based on atan approximation above.
+ *
+ * The special cases around 0 and infinity were tested explicitly.
+ *
+ * The only case not handled correctly is x=NaN,y=0 which returns 0 instead
+ * of nan.
+ */
+ const float a = fabsf(x);
+ const float b = fabsf(y);
+
+ const float k = (b == 0) ? 0.0f : ((a == b) ? 1.0f : (b > a ? a / b : b / a));
+ const float s = 1.0f - (1.0f - k); /* Crush denormals */
+ const float t = s * s;
+
+ float r = s * madd(0.43157974f, t, 1.0f) / madd(madd(0.05831938f, t, 0.76443945f), t, 1.0f);
+
+ if (b > a) {
+ /* Account for arg reduction. */
+ r = M_PI_2_F - r;
+ }
+ /* Test sign bit of x. */
+ if (__float_as_uint(x) & 0x80000000u) {
+ r = M_PI_F - r;
+ }
+ return copysignf(r, y);
+}
+
+/* Based on:
+ *
+ * https://github.com/LiraNuna/glsl-sse2/blob/master/source/vec4.h
+ */
+ccl_device float fast_log2f(float x)
+{
+ /* NOTE: clamp to avoid special cases and make result "safe" from large
+ * negative values/NAN's. */
+ x = clamp(x, FLT_MIN, FLT_MAX);
+ unsigned bits = __float_as_uint(x);
+ int exponent = (int)(bits >> 23) - 127;
+ float f = __uint_as_float((bits & 0x007FFFFF) | 0x3f800000) - 1.0f;
+ /* Examined 2130706432 values of log2 on [1.17549435e-38,3.40282347e+38]:
+ * 0.0797524457 avg ulp diff, 3713596 max ulp, 7.62939e-06 max error.
+ * ulp histogram:
+ * 0 = 97.46%
+ * 1 = 2.29%
+ * 2 = 0.11%
+ */
+ float f2 = f * f;
+ float f4 = f2 * f2;
+ float hi = madd(f, -0.00931049621349f, 0.05206469089414f);
+ float lo = madd(f, 0.47868480909345f, -0.72116591947498f);
+ hi = madd(f, hi, -0.13753123777116f);
+ hi = madd(f, hi, 0.24187369696082f);
+ hi = madd(f, hi, -0.34730547155299f);
+ lo = madd(f, lo, 1.442689881667200f);
+ return ((f4 * hi) + (f * lo)) + exponent;
+}
+
+ccl_device_inline float fast_logf(float x)
+{
+ /* Examined 2130706432 values of logf on [1.17549435e-38,3.40282347e+38]:
+ * 0.313865375 avg ulp diff, 5148137 max ulp, 7.62939e-06 max error.
+ */
+ return fast_log2f(x) * M_LN2_F;
+}
+
+ccl_device_inline float fast_log10(float x)
+{
+ /* Examined 2130706432 values of log10f on [1.17549435e-38,3.40282347e+38]:
+ * 0.631237033 avg ulp diff, 4471615 max ulp, 3.8147e-06 max error.
+ */
+ return fast_log2f(x) * M_LN2_F / M_LN10_F;
+}
+
+ccl_device float fast_logb(float x)
+{
+ /* Don't bother with denormals. */
+ x = fabsf(x);
+ x = clamp(x, FLT_MIN, FLT_MAX);
+ unsigned bits = __float_as_uint(x);
+ return (float)((int)(bits >> 23) - 127);
+}
+
+ccl_device float fast_exp2f(float x)
+{
+ /* Clamp to safe range for final addition. */
+ x = clamp(x, -126.0f, 126.0f);
+ /* Range reduction. */
+ int m = (int)x;
+ x -= m;
+ x = 1.0f - (1.0f - x); /* Crush denormals (does not affect max ulps!). */
+ /* 5th degree polynomial generated with sollya
+ * Examined 2247622658 values of exp2 on [-126,126]: 2.75764912 avg ulp diff,
+ * 232 max ulp.
+ *
+ * ulp histogram:
+ * 0 = 87.81%
+ * 1 = 4.18%
+ */
+ float r = 1.33336498402e-3f;
+ r = madd(x, r, 9.810352697968e-3f);
+ r = madd(x, r, 5.551834031939e-2f);
+ r = madd(x, r, 0.2401793301105f);
+ r = madd(x, r, 0.693144857883f);
+ r = madd(x, r, 1.0f);
+ /* Multiply by 2 ^ m by adding in the exponent. */
+ /* NOTE: left-shift of negative number is undefined behavior. */
+ return __uint_as_float(__float_as_uint(r) + ((unsigned)m << 23));
+}
+
+ccl_device_inline float fast_expf(float x)
+{
+ /* Examined 2237485550 values of exp on [-87.3300018,87.3300018]:
+ * 2.6666452 avg ulp diff, 230 max ulp.
+ */
+ return fast_exp2f(x / M_LN2_F);
+}
+
+#if defined(__KERNEL_CPU__) && !defined(_MSC_VER)
+/* MSVC seems to have a code-gen bug here in at least SSE41/AVX, see
+ * T78047 and T78869 for details. Just disable for now, it only makes
+ * a small difference in denoising performance. */
+ccl_device float4 fast_exp2f4(float4 x)
+{
+ const float4 one = make_float4(1.0f);
+ const float4 limit = make_float4(126.0f);
+ x = clamp(x, -limit, limit);
+ int4 m = make_int4(x);
+ x = one - (one - (x - make_float4(m)));
+ float4 r = make_float4(1.33336498402e-3f);
+ r = madd4(x, r, make_float4(9.810352697968e-3f));
+ r = madd4(x, r, make_float4(5.551834031939e-2f));
+ r = madd4(x, r, make_float4(0.2401793301105f));
+ r = madd4(x, r, make_float4(0.693144857883f));
+ r = madd4(x, r, make_float4(1.0f));
+ return __int4_as_float4(__float4_as_int4(r) + (m << 23));
+}
+
+ccl_device_inline float4 fast_expf4(float4 x)
+{
+ return fast_exp2f4(x / M_LN2_F);
+}
+#else
+ccl_device_inline float4 fast_expf4(float4 x)
+{
+ return make_float4(fast_expf(x.x), fast_expf(x.y), fast_expf(x.z), fast_expf(x.w));
+}
+#endif
+
+ccl_device_inline float fast_exp10(float x)
+{
+ /* Examined 2217701018 values of exp10 on [-37.9290009,37.9290009]:
+ * 2.71732409 avg ulp diff, 232 max ulp.
+ */
+ return fast_exp2f(x * M_LN10_F / M_LN2_F);
+}
+
+ccl_device_inline float fast_expm1f(float x)
+{
+ if (fabsf(x) < 1e-5f) {
+ x = 1.0f - (1.0f - x); /* Crush denormals. */
+ return madd(0.5f, x * x, x);
+ }
+ else {
+ return fast_expf(x) - 1.0f;
+ }
+}
+
+ccl_device float fast_sinhf(float x)
+{
+ float a = fabsf(x);
+ if (a > 1.0f) {
+ /* Examined 53389559 values of sinh on [1,87.3300018]:
+ * 33.6886442 avg ulp diff, 178 max ulp. */
+ float e = fast_expf(a);
+ return copysignf(0.5f * e - 0.5f / e, x);
+ }
+ else {
+ a = 1.0f - (1.0f - a); /* Crush denorms. */
+ float a2 = a * a;
+ /* Degree 7 polynomial generated with sollya. */
+ /* Examined 2130706434 values of sinh on [-1,1]: 1.19209e-07 max error. */
+ float r = 2.03945513931e-4f;
+ r = madd(r, a2, 8.32990277558e-3f);
+ r = madd(r, a2, 0.1666673421859f);
+ r = madd(r * a, a2, a);
+ return copysignf(r, x);
+ }
+}
+
+ccl_device_inline float fast_coshf(float x)
+{
+ /* Examined 2237485550 values of cosh on [-87.3300018,87.3300018]:
+ * 1.78256726 avg ulp diff, 178 max ulp.
+ */
+ float e = fast_expf(fabsf(x));
+ return 0.5f * e + 0.5f / e;
+}
+
+ccl_device_inline float fast_tanhf(float x)
+{
+ /* Examined 4278190080 values of tanh on [-3.40282347e+38,3.40282347e+38]:
+ * 3.12924e-06 max error.
+ */
+ /* NOTE: ulp error is high because of sub-optimal handling around the origin. */
+ float e = fast_expf(2.0f * fabsf(x));
+ return copysignf(1.0f - 2.0f / (1.0f + e), x);
+}
+
+ccl_device float fast_safe_powf(float x, float y)
+{
+ if (y == 0)
+ return 1.0f; /* x^1=1 */
+ if (x == 0)
+ return 0.0f; /* 0^y=0 */
+ float sign = 1.0f;
+ if (x < 0.0f) {
+ /* if x is negative, only deal with integer powers
+ * powf returns NaN for non-integers, we will return 0 instead.
+ */
+ int ybits = __float_as_int(y) & 0x7fffffff;
+ if (ybits >= 0x4b800000) {
+ // always even int, keep positive
+ }
+ else if (ybits >= 0x3f800000) {
+ /* Bigger than 1, check. */
+ int k = (ybits >> 23) - 127; /* Get exponent. */
+ int j = ybits >> (23 - k); /* Shift out possible fractional bits. */
+ if ((j << (23 - k)) == ybits) { /* rebuild number and check for a match. */
+ /* +1 for even, -1 for odd. */
+ sign = __int_as_float(0x3f800000 | (j << 31));
+ }
+ else {
+ /* Not an integer. */
+ return 0.0f;
+ }
+ }
+ else {
+ /* Not an integer. */
+ return 0.0f;
+ }
+ }
+ return sign * fast_exp2f(y * fast_log2f(fabsf(x)));
+}
+
+/* TODO(sergey): Check speed with our erf functions implementation from
+ * bsdf_microfacet.h.
+ */
+
+ccl_device_inline float fast_erff(float x)
+{
+ /* Examined 1082130433 values of erff on [0,4]: 1.93715e-06 max error. */
+ /* Abramowitz and Stegun, 7.1.28. */
+ const float a1 = 0.0705230784f;
+ const float a2 = 0.0422820123f;
+ const float a3 = 0.0092705272f;
+ const float a4 = 0.0001520143f;
+ const float a5 = 0.0002765672f;
+ const float a6 = 0.0000430638f;
+ const float a = fabsf(x);
+ if (a >= 12.3f) {
+ return copysignf(1.0f, x);
+ }
+ const float b = 1.0f - (1.0f - a); /* Crush denormals. */
+ const float r = madd(
+ madd(madd(madd(madd(madd(a6, b, a5), b, a4), b, a3), b, a2), b, a1), b, 1.0f);
+ const float s = r * r; /* ^2 */
+ const float t = s * s; /* ^4 */
+ const float u = t * t; /* ^8 */
+ const float v = u * u; /* ^16 */
+ return copysignf(1.0f - 1.0f / v, x);
+}
+
+ccl_device_inline float fast_erfcf(float x)
+{
+ /* Examined 2164260866 values of erfcf on [-4,4]: 1.90735e-06 max error.
+ *
+ * ulp histogram:
+ *
+ * 0 = 80.30%
+ */
+ return 1.0f - fast_erff(x);
+}
+
+ccl_device_inline float fast_ierff(float x)
+{
+ /* From: Approximating the `erfinv` function by Mike Giles. */
+ /* To avoid trouble at the limit, clamp input to 1-eps. */
+ float a = fabsf(x);
+ if (a > 0.99999994f) {
+ a = 0.99999994f;
+ }
+ float w = -fast_logf((1.0f - a) * (1.0f + a)), p;
+ if (w < 5.0f) {
+ w = w - 2.5f;
+ p = 2.81022636e-08f;
+ p = madd(p, w, 3.43273939e-07f);
+ p = madd(p, w, -3.5233877e-06f);
+ p = madd(p, w, -4.39150654e-06f);
+ p = madd(p, w, 0.00021858087f);
+ p = madd(p, w, -0.00125372503f);
+ p = madd(p, w, -0.00417768164f);
+ p = madd(p, w, 0.246640727f);
+ p = madd(p, w, 1.50140941f);
+ }
+ else {
+ w = sqrtf(w) - 3.0f;
+ p = -0.000200214257f;
+ p = madd(p, w, 0.000100950558f);
+ p = madd(p, w, 0.00134934322f);
+ p = madd(p, w, -0.00367342844f);
+ p = madd(p, w, 0.00573950773f);
+ p = madd(p, w, -0.0076224613f);
+ p = madd(p, w, 0.00943887047f);
+ p = madd(p, w, 1.00167406f);
+ p = madd(p, w, 2.83297682f);
+ }
+ return p * x;
+}
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_FAST_MATH__ */
diff --git a/intern/cycles/util/math_float2.h b/intern/cycles/util/math_float2.h
new file mode 100644
index 00000000000..8ff75c6c20a
--- /dev/null
+++ b/intern/cycles/util/math_float2.h
@@ -0,0 +1,274 @@
+/*
+ * 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.
+ */
+
+#if !defined(__KERNEL_METAL__)
+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);
+#endif /* !__KERNEL_METAL__ */
+
+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);
+}
+
+#if !defined(__KERNEL_METAL__)
+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));
+}
+
+#endif /* !__KERNEL_METAL__ */
+
+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..74f1c98e649
--- /dev/null
+++ b/intern/cycles/util/math_float3.h
@@ -0,0 +1,574 @@
+/*
+ * 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.
+ */
+
+#if !defined(__KERNEL_METAL__)
+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 float3 reflect(const float3 incident, const float3 normal);
+#endif /* !defined(__KERNEL_METAL__) */
+
+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 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, ccl_private float *t);
+ccl_device_inline float3 safe_normalize_len(const float3 a, ccl_private 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);
+}
+
+#if defined(__KERNEL_METAL__)
+
+ccl_device_inline float3 rcp(float3 a)
+{
+ return make_float3(1.0f / a.x, 1.0f / a.y, 1.0f / a.z);
+}
+
+#else
+
+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;
+}
+
+# if !(defined(__KERNEL_METAL__) || defined(__KERNEL_CUDA__))
+ccl_device_inline packed_float3 operator*=(packed_float3 &a, const float3 &b)
+{
+ a = float3(a) * b;
+ return a;
+}
+
+ccl_device_inline packed_float3 operator*=(packed_float3 &a, float f)
+{
+ a = float3(a) * f;
+ return a;
+}
+
+ccl_device_inline packed_float3 operator/=(packed_float3 &a, const float3 &b)
+{
+ a = float3(a) / b;
+ return a;
+}
+
+ccl_device_inline packed_float3 operator/=(packed_float3 &a, float f)
+{
+ a = float3(a) / f;
+ return a;
+}
+# endif
+
+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
+}
+#endif /* !__KERNEL_METAL__ */
+
+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);
+}
+
+#if !defined(__KERNEL_METAL__)
+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;
+}
+#endif
+
+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)
+{
+#if defined(__KERNEL_METAL__)
+ return all(a == b);
+#else
+ return a == b;
+#endif
+}
+
+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..1203a10cca4
--- /dev/null
+++ b/intern/cycles/util/math_float4.h
@@ -0,0 +1,541 @@
+/*
+ * 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.
+ */
+
+#if !defined(__KERNEL_METAL__)
+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);
+#endif /* !__KERNEL_METAL__*/
+
+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);
+}
+
+#if !defined(__KERNEL_METAL__)
+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);
+}
+
+#endif /* !__KERNEL_METAL__*/
+
+#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..39dc3b28f11
--- /dev/null
+++ b/intern/cycles/util/math_int2.h
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+#if !defined(__KERNEL_METAL__)
+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);
+#endif /* !__KERNEL_METAL__ */
+
+/*******************************************************************************
+ * Definition.
+ */
+
+#if !defined(__KERNEL_METAL__)
+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);
+}
+#endif /* !__KERNEL_METAL__ */
+
+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..a09c68ef49a
--- /dev/null
+++ b/intern/cycles/util/math_int3.h
@@ -0,0 +1,114 @@
+/*
+ * 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.
+ */
+
+#if !defined(__KERNEL_METAL__)
+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);
+#endif /* !defined(__KERNEL_METAL__) */
+
+/*******************************************************************************
+ * Definition.
+ */
+
+#if !defined(__KERNEL_METAL__)
+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
+}
+#endif /* !__KERNEL_METAL__ */
+
+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..eaa9be73b63
--- /dev/null
+++ b/intern/cycles/util/math_int4.h
@@ -0,0 +1,153 @@
+/*
+ * 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__
+ return int4(_mm_or_si128(_mm_and_si128(mask, a), _mm_andnot_si128(mask, 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/math_intersect.h b/intern/cycles/util/math_intersect.h
new file mode 100644
index 00000000000..0fce9ff24fd
--- /dev/null
+++ b/intern/cycles/util/math_intersect.h
@@ -0,0 +1,232 @@
+/*
+ * 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_INTERSECT_H__
+#define __UTIL_MATH_INTERSECT_H__
+
+CCL_NAMESPACE_BEGIN
+
+/* Ray Intersection */
+
+ccl_device bool ray_sphere_intersect(float3 ray_P,
+ float3 ray_D,
+ float ray_t,
+ float3 sphere_P,
+ float sphere_radius,
+ ccl_private float3 *isect_P,
+ ccl_private float *isect_t)
+{
+ const float3 d = sphere_P - ray_P;
+ const float radiussq = sphere_radius * sphere_radius;
+ const float tsq = dot(d, d);
+
+ if (tsq > radiussq) {
+ /* Ray origin outside sphere. */
+ const float tp = dot(d, ray_D);
+ if (tp < 0.0f) {
+ /* Ray points away from sphere. */
+ return false;
+ }
+ const float dsq = tsq - tp * tp; /* Pythagoras. */
+ if (dsq > radiussq) {
+ /* Closest point on ray outside sphere. */
+ return false;
+ }
+ const float t = tp - sqrtf(radiussq - dsq); /* pythagoras */
+ if (t < ray_t) {
+ *isect_t = t;
+ *isect_P = ray_P + ray_D * t;
+ return true;
+ }
+ }
+ return false;
+}
+
+ccl_device bool ray_aligned_disk_intersect(float3 ray_P,
+ float3 ray_D,
+ float ray_t,
+ float3 disk_P,
+ float disk_radius,
+ ccl_private float3 *isect_P,
+ ccl_private float *isect_t)
+{
+ /* Aligned disk normal. */
+ float disk_t;
+ const float3 disk_N = normalize_len(ray_P - disk_P, &disk_t);
+ const float div = dot(ray_D, disk_N);
+ if (UNLIKELY(div == 0.0f)) {
+ return false;
+ }
+ /* Compute t to intersection point. */
+ const float t = -disk_t / div;
+ if (t < 0.0f || t > ray_t) {
+ return false;
+ }
+ /* Test if within radius. */
+ float3 P = ray_P + ray_D * t;
+ if (len_squared(P - disk_P) > disk_radius * disk_radius) {
+ return false;
+ }
+ *isect_P = P;
+ *isect_t = t;
+ return true;
+}
+
+ccl_device bool ray_disk_intersect(float3 ray_P,
+ float3 ray_D,
+ float ray_t,
+ float3 disk_P,
+ float3 disk_N,
+ float disk_radius,
+ ccl_private float3 *isect_P,
+ ccl_private float *isect_t)
+{
+ const float3 vp = ray_P - disk_P;
+ const float dp = dot(vp, disk_N);
+ const float cos_angle = dot(disk_N, -ray_D);
+ if (dp * cos_angle > 0.f) // front of light
+ {
+ float t = dp / cos_angle;
+ if (t < 0.f) { /* Ray points away from the light. */
+ return false;
+ }
+ float3 P = ray_P + t * ray_D;
+ float3 T = P - disk_P;
+ if (dot(T, T) < sqr(disk_radius) /*&& t > 0.f*/ && t <= ray_t) {
+ *isect_P = ray_P + t * ray_D;
+ *isect_t = t;
+ return true;
+ }
+ }
+ return false;
+}
+
+ccl_device_forceinline bool ray_triangle_intersect(float3 ray_P,
+ float3 ray_dir,
+ float ray_t,
+ const float3 tri_a,
+ const float3 tri_b,
+ const float3 tri_c,
+ ccl_private float *isect_u,
+ ccl_private float *isect_v,
+ ccl_private float *isect_t)
+{
+#define dot3(a, b) dot(a, b)
+ const float3 P = ray_P;
+ const float3 dir = ray_dir;
+
+ /* Calculate vertices relative to ray origin. */
+ const float3 v0 = tri_c - P;
+ const float3 v1 = tri_a - P;
+ const float3 v2 = tri_b - P;
+
+ /* Calculate triangle edges. */
+ const float3 e0 = v2 - v0;
+ const float3 e1 = v0 - v1;
+ const float3 e2 = v1 - v2;
+
+ /* Perform edge tests. */
+ const float U = dot(cross(v2 + v0, e0), ray_dir);
+ const float V = dot(cross(v0 + v1, e1), ray_dir);
+ const float W = dot(cross(v1 + v2, e2), ray_dir);
+
+ const float minUVW = min(U, min(V, W));
+ const float maxUVW = max(U, max(V, W));
+
+ if (minUVW < 0.0f && maxUVW > 0.0f) {
+ return false;
+ }
+
+ /* Calculate geometry normal and denominator. */
+ const float3 Ng1 = cross(e1, e0);
+ // const Vec3vfM Ng1 = stable_triangle_normal(e2,e1,e0);
+ const float3 Ng = Ng1 + Ng1;
+ const float den = dot3(Ng, dir);
+ /* Avoid division by 0. */
+ if (UNLIKELY(den == 0.0f)) {
+ return false;
+ }
+
+ /* Perform depth test. */
+ const float T = dot3(v0, Ng);
+ const int sign_den = (__float_as_int(den) & 0x80000000);
+ const float sign_T = xor_signmask(T, sign_den);
+ if ((sign_T < 0.0f) || (sign_T > ray_t * xor_signmask(den, sign_den))) {
+ return false;
+ }
+
+ const float inv_den = 1.0f / den;
+ *isect_u = U * inv_den;
+ *isect_v = V * inv_den;
+ *isect_t = T * inv_den;
+ return true;
+
+#undef dot3
+}
+
+/* Tests for an intersection between a ray and a quad defined by
+ * its midpoint, normal and sides.
+ * If ellipse is true, hits outside the ellipse that's enclosed by the
+ * quad are rejected.
+ */
+ccl_device bool ray_quad_intersect(float3 ray_P,
+ float3 ray_D,
+ float ray_mint,
+ float ray_maxt,
+ float3 quad_P,
+ float3 quad_u,
+ float3 quad_v,
+ float3 quad_n,
+ ccl_private float3 *isect_P,
+ ccl_private float *isect_t,
+ ccl_private float *isect_u,
+ ccl_private float *isect_v,
+ bool ellipse)
+{
+ /* Perform intersection test. */
+ float t = -(dot(ray_P, quad_n) - dot(quad_P, quad_n)) / dot(ray_D, quad_n);
+ if (t < ray_mint || t > ray_maxt) {
+ return false;
+ }
+ const float3 hit = ray_P + t * ray_D;
+ const float3 inplane = hit - quad_P;
+ const float u = dot(inplane, quad_u) / dot(quad_u, quad_u);
+ if (u < -0.5f || u > 0.5f) {
+ return false;
+ }
+ const float v = dot(inplane, quad_v) / dot(quad_v, quad_v);
+ if (v < -0.5f || v > 0.5f) {
+ return false;
+ }
+ if (ellipse && (u * u + v * v > 0.25f)) {
+ return false;
+ }
+ /* Store the result. */
+ /* TODO(sergey): Check whether we can avoid some checks here. */
+ if (isect_P != NULL)
+ *isect_P = hit;
+ if (isect_t != NULL)
+ *isect_t = t;
+ if (isect_u != NULL)
+ *isect_u = u + 0.5f;
+ if (isect_v != NULL)
+ *isect_v = v + 0.5f;
+ return true;
+}
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_MATH_INTERSECT_H__ */
diff --git a/intern/cycles/util/math_matrix.h b/intern/cycles/util/math_matrix.h
new file mode 100644
index 00000000000..846b028a513
--- /dev/null
+++ b/intern/cycles/util/math_matrix.h
@@ -0,0 +1,454 @@
+/*
+ * 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_MATRIX_H__
+#define __UTIL_MATH_MATRIX_H__
+
+CCL_NAMESPACE_BEGIN
+
+#define MAT(A, size, row, col) A[(row) * (size) + (col)]
+
+/* Variants that use a constant stride on GPUS. */
+#ifdef __KERNEL_GPU__
+# define MATS(A, n, r, c, s) A[((r) * (n) + (c)) * (s)]
+/* Element access when only the lower-triangular elements are stored. */
+# define MATHS(A, r, c, s) A[((r) * ((r) + 1) / 2 + (c)) * (s)]
+# define VECS(V, i, s) V[(i) * (s)]
+#else
+# define MATS(A, n, r, c, s) MAT(A, n, r, c)
+# define MATHS(A, r, c, s) A[(r) * ((r) + 1) / 2 + (c)]
+# define VECS(V, i, s) V[i]
+#endif
+
+/* Zeroing helpers. */
+
+ccl_device_inline void math_vector_zero(ccl_private float *v, int n)
+{
+ for (int i = 0; i < n; i++) {
+ v[i] = 0.0f;
+ }
+}
+
+ccl_device_inline void math_matrix_zero(ccl_private float *A, int n)
+{
+ for (int row = 0; row < n; row++) {
+ for (int col = 0; col <= row; col++) {
+ MAT(A, n, row, col) = 0.0f;
+ }
+ }
+}
+
+/* Elementary vector operations. */
+
+ccl_device_inline void math_vector_add(ccl_private float *a,
+ ccl_private const float *ccl_restrict b,
+ int n)
+{
+ for (int i = 0; i < n; i++) {
+ a[i] += b[i];
+ }
+}
+
+ccl_device_inline void math_vector_mul(ccl_private float *a,
+ ccl_private const float *ccl_restrict b,
+ int n)
+{
+ for (int i = 0; i < n; i++) {
+ a[i] *= b[i];
+ }
+}
+
+ccl_device_inline void math_vector_mul_strided(ccl_global float *a,
+ ccl_private const float *ccl_restrict b,
+ int astride,
+ int n)
+{
+ for (int i = 0; i < n; i++) {
+ a[i * astride] *= b[i];
+ }
+}
+
+ccl_device_inline void math_vector_scale(ccl_private float *a, float b, int n)
+{
+ for (int i = 0; i < n; i++) {
+ a[i] *= b;
+ }
+}
+
+ccl_device_inline void math_vector_max(ccl_private float *a,
+ ccl_private const float *ccl_restrict b,
+ int n)
+{
+ for (int i = 0; i < n; i++) {
+ a[i] = max(a[i], b[i]);
+ }
+}
+
+ccl_device_inline void math_vec3_add(ccl_private float3 *v, int n, ccl_private float *x, float3 w)
+{
+ for (int i = 0; i < n; i++) {
+ v[i] += w * x[i];
+ }
+}
+
+ccl_device_inline void math_vec3_add_strided(
+ ccl_global float3 *v, int n, ccl_private float *x, float3 w, int stride)
+{
+ for (int i = 0; i < n; i++) {
+ ccl_global float *elem = (ccl_global float *)(v + i * stride);
+ atomic_add_and_fetch_float(elem + 0, w.x * x[i]);
+ atomic_add_and_fetch_float(elem + 1, w.y * x[i]);
+ atomic_add_and_fetch_float(elem + 2, w.z * x[i]);
+ }
+}
+
+/* Elementary matrix operations.
+ * NOTE: TriMatrix refers to a square matrix that is symmetric,
+ * and therefore its upper-triangular part isn't stored. */
+
+ccl_device_inline void math_trimatrix_add_diagonal(ccl_global float *A,
+ int n,
+ float val,
+ int stride)
+{
+ for (int row = 0; row < n; row++) {
+ MATHS(A, row, row, stride) += val;
+ }
+}
+
+/* Add Gramian matrix of v to A.
+ * The Gramian matrix of v is vt*v, so element (i,j) is v[i]*v[j]. */
+ccl_device_inline void math_matrix_add_gramian(ccl_private float *A,
+ int n,
+ ccl_private const float *ccl_restrict v,
+ float weight)
+{
+ for (int row = 0; row < n; row++) {
+ for (int col = 0; col <= row; col++) {
+ MAT(A, n, row, col) += v[row] * v[col] * weight;
+ }
+ }
+}
+
+/* Add Gramian matrix of v to A.
+ * The Gramian matrix of v is vt*v, so element (i,j) is v[i]*v[j]. */
+ccl_device_inline void math_trimatrix_add_gramian_strided(
+ ccl_global float *A, int n, ccl_private const float *ccl_restrict v, float weight, int stride)
+{
+ for (int row = 0; row < n; row++) {
+ for (int col = 0; col <= row; col++) {
+ atomic_add_and_fetch_float(&MATHS(A, row, col, stride), v[row] * v[col] * weight);
+ }
+ }
+}
+
+ccl_device_inline void math_trimatrix_add_gramian(ccl_global float *A,
+ int n,
+ ccl_private const float *ccl_restrict v,
+ float weight)
+{
+ for (int row = 0; row < n; row++) {
+ for (int col = 0; col <= row; col++) {
+ atomic_add_and_fetch_float(&MATHS(A, row, col, 1), v[row] * v[col] * weight);
+ }
+ }
+}
+
+/* Transpose matrix A in place. */
+ccl_device_inline void math_matrix_transpose(ccl_global float *A, int n, int stride)
+{
+ for (int i = 0; i < n; i++) {
+ for (int j = 0; j < i; j++) {
+ float temp = MATS(A, n, i, j, stride);
+ MATS(A, n, i, j, stride) = MATS(A, n, j, i, stride);
+ MATS(A, n, j, i, stride) = temp;
+ }
+ }
+}
+
+/* Solvers for matrix problems */
+
+/* In-place Cholesky-Banachiewicz decomposition of the square, positive-definite matrix A
+ * into a lower triangular matrix L so that A = L*L^T. A is being overwritten by L.
+ * Also, only the lower triangular part of A is ever accessed. */
+ccl_device void math_trimatrix_cholesky(ccl_global float *A, int n, int stride)
+{
+ for (int row = 0; row < n; row++) {
+ for (int col = 0; col <= row; col++) {
+ float sum_col = MATHS(A, row, col, stride);
+ for (int k = 0; k < col; k++) {
+ sum_col -= MATHS(A, row, k, stride) * MATHS(A, col, k, stride);
+ }
+ if (row == col) {
+ sum_col = sqrtf(max(sum_col, 0.0f));
+ }
+ else {
+ sum_col /= MATHS(A, col, col, stride);
+ }
+ MATHS(A, row, col, stride) = sum_col;
+ }
+ }
+}
+
+/* Solve A*S=y for S given A and y,
+ * where A is symmetrical positive-semi-definite and both inputs are destroyed in the process.
+ *
+ * We can apply Cholesky decomposition to find a lower triangular L so that L*Lt = A.
+ * With that we get (L*Lt)*S = L*(Lt*S) = L*b = y, defining b as Lt*S.
+ * Since L is lower triangular, finding b is relatively easy since y is known.
+ * Then, the remaining problem is Lt*S = b, which again can be solved easily.
+ *
+ * This is useful for solving the normal equation S=inv(Xt*W*X)*Xt*W*y, since Xt*W*X is
+ * symmetrical positive-semidefinite by construction,
+ * so we can just use this function with A=Xt*W*X and y=Xt*W*y. */
+ccl_device_inline void math_trimatrix_vec3_solve(ccl_global float *A,
+ ccl_global float3 *y,
+ int n,
+ int stride)
+{
+ /* Since the first entry of the design row is always 1, the upper-left element of XtWX is a good
+ * heuristic for the amount of pixels considered (with weighting),
+ * therefore the amount of correction is scaled based on it. */
+ math_trimatrix_add_diagonal(A, n, 3e-7f * A[0], stride); /* Improve the numerical stability. */
+ math_trimatrix_cholesky(A, n, stride); /* Replace A with L so that L*Lt = A. */
+
+ /* Use forward substitution to solve L*b = y, replacing y by b. */
+ for (int row = 0; row < n; row++) {
+ float3 sum = VECS(y, row, stride);
+ for (int col = 0; col < row; col++)
+ sum -= MATHS(A, row, col, stride) * VECS(y, col, stride);
+ VECS(y, row, stride) = sum / MATHS(A, row, row, stride);
+ }
+
+ /* Use backward substitution to solve Lt*S = b, replacing b by S. */
+ for (int row = n - 1; row >= 0; row--) {
+ float3 sum = VECS(y, row, stride);
+ for (int col = row + 1; col < n; col++)
+ sum -= MATHS(A, col, row, stride) * VECS(y, col, stride);
+ VECS(y, row, stride) = sum / MATHS(A, row, row, stride);
+ }
+}
+
+/* Perform the Jacobi Eigenvalue Method on matrix A.
+ * A is assumed to be a symmetrical matrix, therefore only the lower-triangular part is ever
+ * accessed. The algorithm overwrites the contents of A.
+ *
+ * After returning, A will be overwritten with D, which is (almost) diagonal,
+ * and V will contain the eigenvectors of the original A in its rows (!),
+ * so that A = V^T*D*V. Therefore, the diagonal elements of D are the (sorted) eigenvalues of A.
+ */
+ccl_device void math_matrix_jacobi_eigendecomposition(ccl_private float *A,
+ ccl_global float *V,
+ int n,
+ int v_stride)
+{
+ const float singular_epsilon = 1e-9f;
+
+ for (int row = 0; row < n; row++) {
+ for (int col = 0; col < n; col++) {
+ MATS(V, n, row, col, v_stride) = (col == row) ? 1.0f : 0.0f;
+ }
+ }
+
+ for (int sweep = 0; sweep < 8; sweep++) {
+ float off_diagonal = 0.0f;
+ for (int row = 1; row < n; row++) {
+ for (int col = 0; col < row; col++) {
+ off_diagonal += fabsf(MAT(A, n, row, col));
+ }
+ }
+ if (off_diagonal < 1e-7f) {
+ /* The matrix has nearly reached diagonal form.
+ * Since the eigenvalues are only used to determine truncation, their exact values aren't
+ * required - a relative error of a few ULPs won't matter at all. */
+ break;
+ }
+
+ /* Set the threshold for the small element rotation skip in the first sweep:
+ * Skip all elements that are less than a tenth of the average off-diagonal element. */
+ float threshold = 0.2f * off_diagonal / (n * n);
+
+ for (int row = 1; row < n; row++) {
+ for (int col = 0; col < row; col++) {
+ /* Perform a Jacobi rotation on this element that reduces it to zero. */
+ float element = MAT(A, n, row, col);
+ float abs_element = fabsf(element);
+
+ /* If we're in a later sweep and the element already is very small,
+ * just set it to zero and skip the rotation. */
+ if (sweep > 3 && abs_element <= singular_epsilon * fabsf(MAT(A, n, row, row)) &&
+ abs_element <= singular_epsilon * fabsf(MAT(A, n, col, col))) {
+ MAT(A, n, row, col) = 0.0f;
+ continue;
+ }
+
+ if (element == 0.0f) {
+ continue;
+ }
+
+ /* If we're in one of the first sweeps and the element is smaller than the threshold,
+ * skip it. */
+ if (sweep < 3 && (abs_element < threshold)) {
+ continue;
+ }
+
+ /* Determine rotation: The rotation is characterized by its angle phi - or,
+ * in the actual implementation, sin(phi) and cos(phi).
+ * To find those, we first compute their ratio - that might be unstable if the angle
+ * approaches 90°, so there's a fallback for that case.
+ * Then, we compute sin(phi) and cos(phi) themselves. */
+ float singular_diff = MAT(A, n, row, row) - MAT(A, n, col, col);
+ float ratio;
+ if (abs_element > singular_epsilon * fabsf(singular_diff)) {
+ float cot_2phi = 0.5f * singular_diff / element;
+ ratio = 1.0f / (fabsf(cot_2phi) + sqrtf(1.0f + cot_2phi * cot_2phi));
+ if (cot_2phi < 0.0f)
+ ratio = -ratio; /* Copy sign. */
+ }
+ else {
+ ratio = element / singular_diff;
+ }
+
+ float c = 1.0f / sqrtf(1.0f + ratio * ratio);
+ float s = ratio * c;
+ /* To improve numerical stability by avoiding cancellation, the update equations are
+ * reformulized to use sin(phi) and tan(phi/2) instead. */
+ float tan_phi_2 = s / (1.0f + c);
+
+ /* Update the singular values in the diagonal. */
+ float singular_delta = ratio * element;
+ MAT(A, n, row, row) += singular_delta;
+ MAT(A, n, col, col) -= singular_delta;
+
+ /* Set the element itself to zero. */
+ MAT(A, n, row, col) = 0.0f;
+
+ /* Perform the actual rotations on the matrices. */
+#define ROT(M, r1, c1, r2, c2, stride) \
+ { \
+ float M1 = MATS(M, n, r1, c1, stride); \
+ float M2 = MATS(M, n, r2, c2, stride); \
+ MATS(M, n, r1, c1, stride) -= s * (M2 + tan_phi_2 * M1); \
+ MATS(M, n, r2, c2, stride) += s * (M1 - tan_phi_2 * M2); \
+ }
+
+ /* Split into three parts to ensure correct accesses since we only store the
+ * lower-triangular part of A. */
+ for (int i = 0; i < col; i++)
+ ROT(A, col, i, row, i, 1);
+ for (int i = col + 1; i < row; i++)
+ ROT(A, i, col, row, i, 1);
+ for (int i = row + 1; i < n; i++)
+ ROT(A, i, col, i, row, 1);
+
+ for (int i = 0; i < n; i++)
+ ROT(V, col, i, row, i, v_stride);
+#undef ROT
+ }
+ }
+ }
+
+ /* Sort eigenvalues and the associated eigenvectors. */
+ for (int i = 0; i < n - 1; i++) {
+ float v = MAT(A, n, i, i);
+ int k = i;
+ for (int j = i; j < n; j++) {
+ if (MAT(A, n, j, j) >= v) {
+ v = MAT(A, n, j, j);
+ k = j;
+ }
+ }
+ if (k != i) {
+ /* Swap eigenvalues. */
+ MAT(A, n, k, k) = MAT(A, n, i, i);
+ MAT(A, n, i, i) = v;
+ /* Swap eigenvectors. */
+ for (int j = 0; j < n; j++) {
+ float v = MATS(V, n, i, j, v_stride);
+ MATS(V, n, i, j, v_stride) = MATS(V, n, k, j, v_stride);
+ MATS(V, n, k, j, v_stride) = v;
+ }
+ }
+ }
+}
+
+#ifdef __KERNEL_SSE3__
+ccl_device_inline void math_vector_zero_sse(float4 *A, int n)
+{
+ for (int i = 0; i < n; i++) {
+ A[i] = make_float4(0.0f);
+ }
+}
+
+ccl_device_inline void math_matrix_zero_sse(float4 *A, int n)
+{
+ for (int row = 0; row < n; row++) {
+ for (int col = 0; col <= row; col++) {
+ MAT(A, n, row, col) = make_float4(0.0f);
+ }
+ }
+}
+
+/* Add Gramian matrix of v to A.
+ * The Gramian matrix of v is v^T*v, so element (i,j) is v[i]*v[j]. */
+ccl_device_inline void math_matrix_add_gramian_sse(float4 *A,
+ int n,
+ const float4 *ccl_restrict v,
+ float4 weight)
+{
+ for (int row = 0; row < n; row++) {
+ for (int col = 0; col <= row; col++) {
+ MAT(A, n, row, col) = MAT(A, n, row, col) + v[row] * v[col] * weight;
+ }
+ }
+}
+
+ccl_device_inline void math_vector_add_sse(float4 *V, int n, const float4 *ccl_restrict a)
+{
+ for (int i = 0; i < n; i++) {
+ V[i] += a[i];
+ }
+}
+
+ccl_device_inline void math_vector_mul_sse(float4 *V, int n, const float4 *ccl_restrict a)
+{
+ for (int i = 0; i < n; i++) {
+ V[i] *= a[i];
+ }
+}
+
+ccl_device_inline void math_vector_max_sse(float4 *a, const float4 *ccl_restrict b, int n)
+{
+ for (int i = 0; i < n; i++) {
+ a[i] = max(a[i], b[i]);
+ }
+}
+
+ccl_device_inline void math_matrix_hsum(float *A, int n, const float4 *ccl_restrict B)
+{
+ for (int row = 0; row < n; row++) {
+ for (int col = 0; col <= row; col++) {
+ MAT(A, n, row, col) = reduce_add(MAT(B, n, row, col))[0];
+ }
+ }
+}
+#endif
+
+#undef MAT
+
+CCL_NAMESPACE_END
+
+#endif /* __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..4efdeeae7f0
--- /dev/null
+++ b/intern/cycles/util/path.cpp
@@ -0,0 +1,931 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_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_source_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)
+{
+ cached_path = path;
+ cached_user_path = user_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
+}
+
+#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 a 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;
+}
+
+struct SourceReplaceState {
+ typedef map<string, string> ProcessedMapping;
+ /* Base director for all relative include headers. */
+ string base;
+ /* Result of processed files. */
+ ProcessedMapping processed_files;
+ /* Set of files containing #pragma once which have been included. */
+ set<string> pragma_onced;
+};
+
+static string path_source_replace_includes_recursive(const string &source,
+ const string &source_filepath,
+ SourceReplaceState *state);
+
+static string path_source_handle_preprocessor(const string &preprocessor_line,
+ const string &source_filepath,
+ SourceReplaceState *state)
+{
+ string result = preprocessor_line;
+
+ string rest_of_line = string_strip(preprocessor_line.substr(1));
+
+ if (0 == strncmp(rest_of_line.c_str(), "include", 7)) {
+ rest_of_line = string_strip(rest_of_line.substr(8));
+ if (rest_of_line[0] == '"') {
+ const size_t n_start = 1;
+ const size_t n_end = rest_of_line.find("\"", n_start);
+ const string filename = rest_of_line.substr(n_start, n_end - n_start);
+
+ string filepath = path_join(state->base, filename);
+ if (!path_exists(filepath)) {
+ filepath = path_join(path_dirname(source_filepath), filename);
+ }
+ string text;
+ if (path_read_text(filepath, text)) {
+ text = path_source_replace_includes_recursive(text, filepath, state);
+ /* Use line directives for better error messages. */
+ return "\n" + text + "\n";
+ }
+ }
+ }
+
+ return result;
+}
+
+/* Our own little c preprocessor that replaces #includes with the file
+ * contents, to work around issue of OpenCL drivers not supporting
+ * include paths with spaces in them.
+ */
+static string path_source_replace_includes_recursive(const string &_source,
+ const string &source_filepath,
+ SourceReplaceState *state)
+{
+ const string *psource = &_source;
+ string source_new;
+
+ auto pragma_once = _source.find("#pragma once");
+ if (pragma_once != string::npos) {
+ if (state->pragma_onced.find(source_filepath) != state->pragma_onced.end()) {
+ return "";
+ }
+ state->pragma_onced.insert(source_filepath);
+
+ // "#pragma once"
+ // "//prgma once"
+ source_new = _source;
+ memcpy(source_new.data() + pragma_once, "//pr", 4);
+ psource = &source_new;
+ }
+
+ /* Try to re-use processed file without spending time on replacing all
+ * include directives again.
+ */
+ SourceReplaceState::ProcessedMapping::iterator replaced_file = state->processed_files.find(
+ source_filepath);
+ if (replaced_file != state->processed_files.end()) {
+ return replaced_file->second;
+ }
+
+ const string &source = *psource;
+
+ /* Perform full file processing. */
+ string result = "";
+ const size_t source_length = source.length();
+ size_t index = 0;
+ /* Information about where we are in the source. */
+ size_t line_number = 0, column_number = 1;
+ /* Currently gathered non-preprocessor token.
+ * Store as start/length rather than token itself to avoid overhead of
+ * memory re-allocations on each character concatenation.
+ */
+ size_t token_start = 0, token_length = 0;
+ /* Denotes whether we're inside of preprocessor line, together with
+ * preprocessor line itself.
+ *
+ * TODO(sergey): Investigate whether using token start/end position
+ * gives measurable speedup.
+ */
+ bool inside_preprocessor = false;
+ string preprocessor_line = "";
+ /* Actual loop over the whole source. */
+ while (index < source_length) {
+ char ch = source[index];
+
+ if (ch == '\n') {
+ if (inside_preprocessor) {
+ string block = path_source_handle_preprocessor(preprocessor_line, source_filepath, state);
+
+ if (!block.empty()) {
+ result += block;
+ }
+
+ /* Start gathering net part of the token. */
+ token_start = index;
+ token_length = 0;
+ inside_preprocessor = false;
+ preprocessor_line = "";
+ }
+ column_number = 0;
+ ++line_number;
+ }
+ else if (ch == '#' && column_number == 1 && !inside_preprocessor) {
+ /* Append all possible non-preprocessor token to the result. */
+ if (token_length != 0) {
+ result.append(source, token_start, token_length);
+ token_start = index;
+ token_length = 0;
+ }
+ inside_preprocessor = true;
+ }
+
+ if (inside_preprocessor) {
+ preprocessor_line += ch;
+ }
+ else {
+ ++token_length;
+ }
+ ++index;
+ ++column_number;
+ }
+ /* Append possible tokens which happened before special events handled
+ * above.
+ */
+ if (token_length != 0) {
+ result.append(source, token_start, token_length);
+ }
+ if (inside_preprocessor) {
+ result += path_source_handle_preprocessor(preprocessor_line, source_filepath, state);
+ }
+ /* Store result for further reuse. */
+ state->processed_files[source_filepath] = result;
+ return result;
+}
+
+string path_source_replace_includes(const string &source, const string &path)
+{
+ SourceReplaceState state;
+ state.base = path;
+ return path_source_replace_includes_recursive(source, path, &state);
+}
+
+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..98c3302eae2
--- /dev/null
+++ b/intern/cycles/util/path.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 = "");
+string path_get(const string &sub = "");
+string path_user_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);
+
+/* source code utility */
+string path_source_replace_includes(const string &source, 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..d6df1b0b807
--- /dev/null
+++ b/intern/cycles/util/profiling.cpp
@@ -0,0 +1,179 @@
+/*
+ * 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;
+}
+
+bool Profiler::active() const
+{
+ return (worker != nullptr);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/util/profiling.h b/intern/cycles/util/profiling.h
new file mode 100644
index 00000000000..4ced1d90371
--- /dev/null
+++ b/intern/cycles/util/profiling.h
@@ -0,0 +1,182 @@
+/*
+ * 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);
+
+ bool active() const;
+
+ 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..15bd26d34bf
--- /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_;
+ }
+
+ double get_progress() const
+ {
+ thread_scoped_lock lock(progress_mutex);
+
+ if (total_pixel_samples > 0) {
+ return ((double)pixel_samples) / (double)total_pixel_samples;
+ }
+ return 0.0;
+ }
+
+ 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..fc496e55a0c
--- /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
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Euclidean 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..61ad552fa89
--- /dev/null
+++ b/intern/cycles/util/system.cpp
@@ -0,0 +1,329 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <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
+
+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;
+}
+
+/* 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..d26c324be0a
--- /dev/null
+++ b/intern/cycles/util/system.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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
+
+/* Get width in characters of the current console output. */
+int system_console_width();
+
+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..174befce571
--- /dev/null
+++ b/intern/cycles/util/task.cpp
@@ -0,0 +1,252 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 = tbb::this_task_arena::max_concurrency();
+ }
+}
+
+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::max_concurrency()
+{
+ thread_scoped_lock lock(mutex);
+ return (users > 0) ? active_num_threads : tbb::this_task_arena::max_concurrency();
+}
+
+/* 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..0117c51d05c
--- /dev/null
+++ b/intern/cycles/util/task.h
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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();
+
+ /* Maximum number of threads that will work on task. Use as little as
+ * possible and leave scheduling and splitting up tasks to the scheduler. */
+ static int max_concurrency();
+
+ 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..e2e785b9a80
--- /dev/null
+++ b/intern/cycles/util/thread.cpp
@@ -0,0 +1,69 @@
+/*
+ * 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) : run_cb_(run_cb), joined_(false)
+{
+#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);
+ 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..bd6a83e1dd1
--- /dev/null
+++ b/intern/cycles/util/thread.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.
+ */
+
+#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:
+ thread(function<void()> run_cb);
+ ~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_;
+};
+
+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..84827cf6ba5
--- /dev/null
+++ b/intern/cycles/util/transform.h
@@ -0,0 +1,527 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 */
+
+#ifdef __KERNEL_METAL__
+/* transform_point specialized for ccl_global */
+ccl_device_inline float3 transform_point(ccl_global const Transform *t, const float3 a)
+{
+ ccl_global const float3x3 &b(*(ccl_global const float3x3 *)t);
+ return (a * b).xyz + make_float3(t->x.w, t->y.w, t->z.w);
+}
+#endif
+
+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);
+#elif defined(__KERNEL_METAL__)
+ ccl_private const float3x3 &b(*(ccl_private const float3x3 *)t);
+ return (a * b).xyz + make_float3(t->x.w, t->y.w, t->z.w);
+#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);
+#elif defined(__KERNEL_METAL__)
+ ccl_private const float3x3 &b(*(ccl_private const float3x3 *)t);
+ return (a * b).xyz;
+#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 and MetalRT are using lerp to interpolate motion transformations. */
+#if defined(__KERNEL_GPU_RAYTRACING__)
+ return normalize((1.0f - t) * q1 + t * q2);
+#else /* defined(__KERNEL_GPU_RAYTRACING__) */
+ /* 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 /* defined(__KERNEL_GPU_RAYTRACING__) */
+}
+
+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(ccl_private Transform *tfm,
+ ccl_global 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;
+
+ ccl_global const DecomposedTransform *a = motion + step;
+ ccl_global 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..58a6d134819
--- /dev/null
+++ b/intern/cycles/util/types.h
@@ -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.
+ */
+
+#ifndef __UTIL_TYPES_H__
+#define __UTIL_TYPES_H__
+
+#if !defined(__KERNEL_METAL__)
+# include <stdlib.h>
+#endif
+
+/* 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..cafcfebf526
--- /dev/null
+++ b/intern/cycles/util/types_float3.h
@@ -0,0 +1,95 @@
+/*
+ * 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__ */
+
+/* Smaller float3 for storage. For math operations this must be converted to float3, so that on the
+ * CPU SIMD instructions can be used. */
+#if defined(__KERNEL_METAL__)
+/* Metal has native packed_float3. */
+#elif defined(__KERNEL_CUDA__)
+/* CUDA float3 is already packed. */
+typedef float3 packed_float3;
+#else
+/* HIP float3 is not packed (https://github.com/ROCm-Developer-Tools/HIP/issues/706). */
+struct packed_float3 {
+ ccl_device_inline_method packed_float3(){};
+
+ ccl_device_inline_method packed_float3(const float3 &a) : x(a.x), y(a.y), z(a.z)
+ {
+ }
+
+ ccl_device_inline_method operator float3() const
+ {
+ return make_float3(x, y, z);
+ }
+
+ ccl_device_inline_method packed_float3 &operator=(const float3 &a)
+ {
+ x = a.x;
+ y = a.y;
+ z = a.z;
+ return *this;
+ }
+
+ float x, y, z;
+};
+#endif
+
+static_assert(sizeof(packed_float3) == 12, "packed_float3 expected to be exactly 12 bytes");
+
+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_atomic.h b/intern/cycles/util/util_atomic.h
deleted file mode 100644
index faba411c769..00000000000
--- a/intern/cycles/util/util_atomic.h
+++ /dev/null
@@ -1,68 +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.
- */
-
-#ifndef __UTIL_ATOMIC_H__
-#define __UTIL_ATOMIC_H__
-
-#ifndef __KERNEL_GPU__
-
-/* Using atomic ops header from Blender. */
-# include "atomic_ops.h"
-
-# define atomic_add_and_fetch_float(p, x) atomic_add_and_fetch_fl((p), (x))
-# define atomic_compare_and_swap_float(p, old_val, new_val) \
- atomic_cas_float((p), (old_val), (new_val))
-
-# define atomic_fetch_and_inc_uint32(p) atomic_fetch_and_add_uint32((p), 1)
-# define atomic_fetch_and_dec_uint32(p) atomic_fetch_and_add_uint32((p), -1)
-
-# define CCL_LOCAL_MEM_FENCE 0
-# define ccl_barrier(flags) ((void)0)
-
-#else /* __KERNEL_GPU__ */
-
-# if defined(__KERNEL_CUDA__) || defined(__KERNEL_HIP__)
-
-# define atomic_add_and_fetch_float(p, x) (atomicAdd((float *)(p), (float)(x)) + (float)(x))
-
-# define atomic_fetch_and_add_uint32(p, x) atomicAdd((unsigned int *)(p), (unsigned int)(x))
-# define atomic_fetch_and_sub_uint32(p, x) atomicSub((unsigned int *)(p), (unsigned int)(x))
-# define atomic_fetch_and_inc_uint32(p) atomic_fetch_and_add_uint32((p), 1)
-# define atomic_fetch_and_dec_uint32(p) atomic_fetch_and_sub_uint32((p), 1)
-# define atomic_fetch_and_or_uint32(p, x) atomicOr((unsigned int *)(p), (unsigned int)(x))
-
-ccl_device_inline float atomic_compare_and_swap_float(volatile float *dest,
- const float old_val,
- const float new_val)
-{
- union {
- unsigned int int_value;
- float float_value;
- } new_value, prev_value, result;
- prev_value.float_value = old_val;
- new_value.float_value = new_val;
- result.int_value = atomicCAS((unsigned int *)dest, prev_value.int_value, new_value.int_value);
- return result.float_value;
-}
-
-# define CCL_LOCAL_MEM_FENCE
-# define ccl_barrier(flags) __syncthreads()
-
-# endif /* __KERNEL_CUDA__ */
-
-#endif /* __KERNEL_GPU__ */
-
-#endif /* __UTIL_ATOMIC_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 7b67b90e44d..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, 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 f36a492a1b0..00000000000
--- a/intern/cycles/util/util_half.h
+++ /dev/null
@@ -1,179 +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;
-};
-
-#if defined(__KERNEL_CUDA__) || defined(__KERNEL_HIP__)
-
-ccl_device_inline void float4_store_half(half *h, float4 f)
-{
- h[0] = __float2half(f.x);
- h[1] = __float2half(f.y);
- h[2] = __float2half(f.z);
- h[3] = __float2half(f.w);
-}
-
-#else
-
-ccl_device_inline void float4_store_half(half *h, float4 f)
-{
-
-# ifndef __KERNEL_SSE2__
- for (int i = 0; i < 4; i++) {
- /* optimized float to half for pixels:
- * assumes no negative, no nan, no inf, and sets denormal to 0 */
- union {
- uint i;
- float f;
- } in;
- in.f = (f[i] > 0.0f) ? ((f[i] < 65504.0f) ? f[i] : 65504.0f) : 0.0f;
- int x = in.i;
-
- int absolute = x & 0x7FFFFFFF;
- int Z = absolute + 0xC8000000;
- int result = (absolute < 0x38800000) ? 0 : Z;
- int rshift = (result >> 13);
-
- h[i] = (rshift & 0x7FFF);
- }
-# else
- /* same as above with SSE */
- 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
-
- _mm_storel_pi((__m64 *)h, _mm_castsi128_ps(rpack));
-# endif
-}
-
-# ifndef __KERNEL_HIP__
-
-ccl_device_inline float half_to_float(half h)
-{
- float f;
-
- *((int *)&f) = ((h & 0x8000) << 16) | (((h & 0x7c00) + 0x1C000) << 13) | ((h & 0x03FF) << 13);
-
- return f;
-}
-# else
-
-ccl_device_inline float half_to_float(std::uint32_t a) noexcept
-{
-
- std::uint32_t u = ((a << 13) + 0x70000000U) & 0x8fffe000U;
-
- std::uint32_t v = __float_as_uint(__uint_as_float(u) *
- __uint_as_float(0x77800000U) /*0x1.0p+112f*/) +
- 0x38000000U;
-
- u = (a & 0x7fff) != 0 ? v : u;
-
- return __uint_as_float(u) * __uint_as_float(0x07800000U) /*0x1.0p-112f*/;
-}
-
-# endif /* __KERNEL_HIP__ */
-
-ccl_device_inline float4 half4_to_float4(half4 h)
-{
- float4 f;
-
- f.x = half_to_float(h.x);
- f.y = half_to_float(h.y);
- f.z = half_to_float(h.z);
- f.w = half_to_float(h.w);
-
- return f;
-}
-
-ccl_device_inline half float_to_half(float f)
-{
- 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_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 27ec7ffb423..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(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(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 cb1e94c838c..00000000000
--- a/intern/cycles/util/util_math.h
+++ /dev/null
@@ -1,836 +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
-}
-
-/* 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, 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(const float3 &v1, const float3 &v2, const float3 &v3)
-{
- return len(cross(v3 - v2, v1 - v2)) * 0.5f;
-}
-
-/* Orthonormal vectors */
-
-ccl_device_inline void make_orthonormals(const float3 N, float3 *a, 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_fast.h b/intern/cycles/util/util_math_fast.h
deleted file mode 100644
index 38afa163db5..00000000000
--- a/intern/cycles/util/util_math_fast.h
+++ /dev/null
@@ -1,652 +0,0 @@
-/*
- * Adapted from OpenImageIO library with this license:
- *
- * Copyright 2008-2014 Larry Gritz and the other authors and contributors.
- * 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 the software's owners 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.
- *
- * (This is the Modified BSD License)
- *
- * A few bits here are based upon code from NVIDIA that was also released
- * under the same modified BSD license, and marked as:
- * Copyright 2004 NVIDIA Corporation. All Rights Reserved.
- *
- * Some parts of this file were first open-sourced in Open Shading Language,
- * then later moved here. The original copyright notice was:
- * Copyright (c) 2009-2014 Sony Pictures Imageworks Inc., et al.
- *
- * Many of the math functions were copied from or inspired by other
- * public domain sources or open source packages with compatible licenses.
- * The individual functions give references were applicable.
- */
-
-#ifndef __UTIL_FAST_MATH__
-#define __UTIL_FAST_MATH__
-
-CCL_NAMESPACE_BEGIN
-
-ccl_device_inline float madd(const float a, const float b, const float c)
-{
- /* NOTE: In the future we may want to explicitly ask for a fused
- * multiply-add in a specialized version for float.
- *
- * NOTE: GCC/ICC will turn this (for float) into a FMA unless
- * explicitly asked not to, clang seems to leave the code alone.
- */
- return a * b + c;
-}
-
-ccl_device_inline float4 madd4(const float4 a, const float4 b, const float4 c)
-{
- return a * b + c;
-}
-
-/*
- * FAST & APPROXIMATE MATH
- *
- * The functions named "fast_*" provide a set of replacements to libm that
- * are much faster at the expense of some accuracy and robust handling of
- * extreme values. One design goal for these approximation was to avoid
- * branches as much as possible and operate on single precision values only
- * so that SIMD versions should be straightforward ports We also try to
- * implement "safe" semantics (ie: clamp to valid range where possible)
- * natively since wrapping these inline calls in another layer would be
- * wasteful.
- *
- * Some functions are fast_safe_*, which is both a faster approximation as
- * well as clamped input domain to ensure no NaN, Inf, or divide by zero.
- */
-
-/* Round to nearest integer, returning as an int. */
-ccl_device_inline int fast_rint(float x)
-{
- /* used by sin/cos/tan range reduction. */
-#ifdef __KERNEL_SSE4__
- /* Single `roundps` instruction on SSE4.1+ (for gcc/clang at least). */
- return float_to_int(rintf(x));
-#else
- /* emulate rounding by adding/subtracting 0.5. */
- return float_to_int(x + copysignf(0.5f, x));
-#endif
-}
-
-ccl_device float fast_sinf(float x)
-{
- /* Very accurate argument reduction from SLEEF,
- * starts failing around x=262000
- *
- * Results on: [-2pi,2pi].
- *
- * Examined 2173837240 values of sin: 0.00662760244 avg ulp diff, 2 max ulp,
- * 1.19209e-07 max error
- */
- int q = fast_rint(x * M_1_PI_F);
- float qf = (float)q;
- x = madd(qf, -0.78515625f * 4, x);
- x = madd(qf, -0.00024187564849853515625f * 4, x);
- x = madd(qf, -3.7747668102383613586e-08f * 4, x);
- x = madd(qf, -1.2816720341285448015e-12f * 4, x);
- x = M_PI_2_F - (M_PI_2_F - x); /* Crush denormals */
- float s = x * x;
- if ((q & 1) != 0)
- x = -x;
- /* This polynomial approximation has very low error on [-pi/2,+pi/2]
- * 1.19209e-07 max error in total over [-2pi,+2pi]. */
- float u = 2.6083159809786593541503e-06f;
- u = madd(u, s, -0.0001981069071916863322258f);
- u = madd(u, s, +0.00833307858556509017944336f);
- u = madd(u, s, -0.166666597127914428710938f);
- u = madd(s, u * x, x);
- /* For large x, the argument reduction can fail and the polynomial can be
- * evaluated with arguments outside the valid internal. Just clamp the bad
- * values away (setting to 0.0f means no branches need to be generated). */
- if (fabsf(u) > 1.0f) {
- u = 0.0f;
- }
- return u;
-}
-
-ccl_device float fast_cosf(float x)
-{
- /* Same argument reduction as fast_sinf(). */
- int q = fast_rint(x * M_1_PI_F);
- float qf = (float)q;
- x = madd(qf, -0.78515625f * 4, x);
- x = madd(qf, -0.00024187564849853515625f * 4, x);
- x = madd(qf, -3.7747668102383613586e-08f * 4, x);
- x = madd(qf, -1.2816720341285448015e-12f * 4, x);
- x = M_PI_2_F - (M_PI_2_F - x); /* Crush denormals. */
- float s = x * x;
- /* Polynomial from SLEEF's sincosf, max error is
- * 4.33127e-07 over [-2pi,2pi] (98% of values are "exact"). */
- float u = -2.71811842367242206819355e-07f;
- u = madd(u, s, +2.47990446951007470488548e-05f);
- u = madd(u, s, -0.00138888787478208541870117f);
- u = madd(u, s, +0.0416666641831398010253906f);
- u = madd(u, s, -0.5f);
- u = madd(u, s, +1.0f);
- if ((q & 1) != 0) {
- u = -u;
- }
- if (fabsf(u) > 1.0f) {
- u = 0.0f;
- }
- return u;
-}
-
-ccl_device void fast_sincosf(float x, float *sine, float *cosine)
-{
- /* Same argument reduction as fast_sin. */
- int q = fast_rint(x * M_1_PI_F);
- float qf = (float)q;
- x = madd(qf, -0.78515625f * 4, x);
- x = madd(qf, -0.00024187564849853515625f * 4, x);
- x = madd(qf, -3.7747668102383613586e-08f * 4, x);
- x = madd(qf, -1.2816720341285448015e-12f * 4, x);
- x = M_PI_2_F - (M_PI_2_F - x); // crush denormals
- float s = x * x;
- /* NOTE: same exact polynomials as fast_sinf() and fast_cosf() above. */
- if ((q & 1) != 0) {
- x = -x;
- }
- float su = 2.6083159809786593541503e-06f;
- su = madd(su, s, -0.0001981069071916863322258f);
- su = madd(su, s, +0.00833307858556509017944336f);
- su = madd(su, s, -0.166666597127914428710938f);
- su = madd(s, su * x, x);
- float cu = -2.71811842367242206819355e-07f;
- cu = madd(cu, s, +2.47990446951007470488548e-05f);
- cu = madd(cu, s, -0.00138888787478208541870117f);
- cu = madd(cu, s, +0.0416666641831398010253906f);
- cu = madd(cu, s, -0.5f);
- cu = madd(cu, s, +1.0f);
- if ((q & 1) != 0) {
- cu = -cu;
- }
- if (fabsf(su) > 1.0f) {
- su = 0.0f;
- }
- if (fabsf(cu) > 1.0f) {
- cu = 0.0f;
- }
- *sine = su;
- *cosine = cu;
-}
-
-/* NOTE: this approximation is only valid on [-8192.0,+8192.0], it starts
- * becoming really poor outside of this range because the reciprocal amplifies
- * errors.
- */
-ccl_device float fast_tanf(float x)
-{
- /* Derived from SLEEF implementation.
- *
- * Note that we cannot apply the "denormal crush" trick everywhere because
- * we sometimes need to take the reciprocal of the polynomial
- */
- int q = fast_rint(x * 2.0f * M_1_PI_F);
- float qf = (float)q;
- x = madd(qf, -0.78515625f * 2, x);
- x = madd(qf, -0.00024187564849853515625f * 2, x);
- x = madd(qf, -3.7747668102383613586e-08f * 2, x);
- x = madd(qf, -1.2816720341285448015e-12f * 2, x);
- if ((q & 1) == 0) {
- /* Crush denormals (only if we aren't inverting the result later). */
- x = M_PI_4_F - (M_PI_4_F - x);
- }
- float s = x * x;
- float u = 0.00927245803177356719970703f;
- u = madd(u, s, 0.00331984995864331722259521f);
- u = madd(u, s, 0.0242998078465461730957031f);
- u = madd(u, s, 0.0534495301544666290283203f);
- u = madd(u, s, 0.133383005857467651367188f);
- u = madd(u, s, 0.333331853151321411132812f);
- u = madd(s, u * x, x);
- if ((q & 1) != 0) {
- u = -1.0f / u;
- }
- return u;
-}
-
-/* Fast, approximate sin(x*M_PI) with maximum absolute error of 0.000918954611.
- *
- * Adapted from http://devmaster.net/posts/9648/fast-and-accurate-sine-cosine#comment-76773
- */
-ccl_device float fast_sinpif(float x)
-{
- /* Fast trick to strip the integral part off, so our domain is [-1, 1]. */
- const float z = x - ((x + 25165824.0f) - 25165824.0f);
- const float y = z - z * fabsf(z);
- const float Q = 3.10396624f;
- const float P = 3.584135056f; /* P = 16-4*Q */
- return y * (Q + P * fabsf(y));
-
- /* The original article used inferior constants for Q and P and
- * so had max error 1.091e-3.
- *
- * The optimal value for Q was determined by exhaustive search, minimizing
- * the absolute numerical error relative to float(std::sin(double(phi*M_PI)))
- * over the interval [0,2] (which is where most of the invocations happen).
- *
- * The basic idea of this approximation starts with the coarse approximation:
- * sin(pi*x) ~= f(x) = 4 * (x - x * abs(x))
- *
- * This approximation always _over_ estimates the target. On the other hand,
- * the curve:
- * sin(pi*x) ~= f(x) * abs(f(x)) / 4
- *
- * always lies _under_ the target. Thus we can simply numerically search for
- * the optimal constant to LERP these curves into a more precise
- * approximation.
- *
- * After folding the constants together and simplifying the resulting math,
- * we end up with the compact implementation above.
- *
- * NOTE: this function actually computes sin(x * pi) which avoids one or two
- * mults in many cases and guarantees exact values at integer periods.
- */
-}
-
-/* Fast approximate cos(x*M_PI) with ~0.1% absolute error. */
-ccl_device_inline float fast_cospif(float x)
-{
- return fast_sinpif(x + 0.5f);
-}
-
-ccl_device float fast_acosf(float x)
-{
- const float f = fabsf(x);
- /* clamp and crush denormals. */
- const float m = (f < 1.0f) ? 1.0f - (1.0f - f) : 1.0f;
- /* Based on http://www.pouet.net/topic.php?which=9132&page=2
- * 85% accurate (ulp 0)
- * Examined 2130706434 values of acos:
- * 15.2000597 avg ulp diff, 4492 max ulp, 4.51803e-05 max error // without "denormal crush"
- * Examined 2130706434 values of acos:
- * 15.2007108 avg ulp diff, 4492 max ulp, 4.51803e-05 max error // with "denormal crush"
- */
- const float a = sqrtf(1.0f - m) *
- (1.5707963267f + m * (-0.213300989f + m * (0.077980478f + m * -0.02164095f)));
- return x < 0 ? M_PI_F - a : a;
-}
-
-ccl_device float fast_asinf(float x)
-{
- /* Based on acosf approximation above.
- * Max error is 4.51133e-05 (ulps are higher because we are consistently off
- * by a little amount).
- */
- const float f = fabsf(x);
- /* Clamp and crush denormals. */
- const float m = (f < 1.0f) ? 1.0f - (1.0f - f) : 1.0f;
- const float a = M_PI_2_F -
- sqrtf(1.0f - m) * (1.5707963267f +
- m * (-0.213300989f + m * (0.077980478f + m * -0.02164095f)));
- return copysignf(a, x);
-}
-
-ccl_device float fast_atanf(float x)
-{
- const float a = fabsf(x);
- const float k = a > 1.0f ? 1 / a : a;
- const float s = 1.0f - (1.0f - k); /* Crush denormals. */
- const float t = s * s;
- /* http://mathforum.org/library/drmath/view/62672.html
- * Examined 4278190080 values of atan:
- * 2.36864877 avg ulp diff, 302 max ulp, 6.55651e-06 max error // (with denormals)
- * Examined 4278190080 values of atan:
- * 171160502 avg ulp diff, 855638016 max ulp, 6.55651e-06 max error // (crush denormals)
- */
- float r = s * madd(0.43157974f, t, 1.0f) / madd(madd(0.05831938f, t, 0.76443945f), t, 1.0f);
- if (a > 1.0f) {
- r = M_PI_2_F - r;
- }
- return copysignf(r, x);
-}
-
-ccl_device float fast_atan2f(float y, float x)
-{
- /* Based on atan approximation above.
- *
- * The special cases around 0 and infinity were tested explicitly.
- *
- * The only case not handled correctly is x=NaN,y=0 which returns 0 instead
- * of nan.
- */
- const float a = fabsf(x);
- const float b = fabsf(y);
-
- const float k = (b == 0) ? 0.0f : ((a == b) ? 1.0f : (b > a ? a / b : b / a));
- const float s = 1.0f - (1.0f - k); /* Crush denormals */
- const float t = s * s;
-
- float r = s * madd(0.43157974f, t, 1.0f) / madd(madd(0.05831938f, t, 0.76443945f), t, 1.0f);
-
- if (b > a) {
- /* Account for arg reduction. */
- r = M_PI_2_F - r;
- }
- /* Test sign bit of x. */
- if (__float_as_uint(x) & 0x80000000u) {
- r = M_PI_F - r;
- }
- return copysignf(r, y);
-}
-
-/* Based on:
- *
- * https://github.com/LiraNuna/glsl-sse2/blob/master/source/vec4.h
- */
-ccl_device float fast_log2f(float x)
-{
- /* NOTE: clamp to avoid special cases and make result "safe" from large
- * negative values/NAN's. */
- x = clamp(x, FLT_MIN, FLT_MAX);
- unsigned bits = __float_as_uint(x);
- int exponent = (int)(bits >> 23) - 127;
- float f = __uint_as_float((bits & 0x007FFFFF) | 0x3f800000) - 1.0f;
- /* Examined 2130706432 values of log2 on [1.17549435e-38,3.40282347e+38]:
- * 0.0797524457 avg ulp diff, 3713596 max ulp, 7.62939e-06 max error.
- * ulp histogram:
- * 0 = 97.46%
- * 1 = 2.29%
- * 2 = 0.11%
- */
- float f2 = f * f;
- float f4 = f2 * f2;
- float hi = madd(f, -0.00931049621349f, 0.05206469089414f);
- float lo = madd(f, 0.47868480909345f, -0.72116591947498f);
- hi = madd(f, hi, -0.13753123777116f);
- hi = madd(f, hi, 0.24187369696082f);
- hi = madd(f, hi, -0.34730547155299f);
- lo = madd(f, lo, 1.442689881667200f);
- return ((f4 * hi) + (f * lo)) + exponent;
-}
-
-ccl_device_inline float fast_logf(float x)
-{
- /* Examined 2130706432 values of logf on [1.17549435e-38,3.40282347e+38]:
- * 0.313865375 avg ulp diff, 5148137 max ulp, 7.62939e-06 max error.
- */
- return fast_log2f(x) * M_LN2_F;
-}
-
-ccl_device_inline float fast_log10(float x)
-{
- /* Examined 2130706432 values of log10f on [1.17549435e-38,3.40282347e+38]:
- * 0.631237033 avg ulp diff, 4471615 max ulp, 3.8147e-06 max error.
- */
- return fast_log2f(x) * M_LN2_F / M_LN10_F;
-}
-
-ccl_device float fast_logb(float x)
-{
- /* Don't bother with denormals. */
- x = fabsf(x);
- x = clamp(x, FLT_MIN, FLT_MAX);
- unsigned bits = __float_as_uint(x);
- return (float)((int)(bits >> 23) - 127);
-}
-
-ccl_device float fast_exp2f(float x)
-{
- /* Clamp to safe range for final addition. */
- x = clamp(x, -126.0f, 126.0f);
- /* Range reduction. */
- int m = (int)x;
- x -= m;
- x = 1.0f - (1.0f - x); /* Crush denormals (does not affect max ulps!). */
- /* 5th degree polynomial generated with sollya
- * Examined 2247622658 values of exp2 on [-126,126]: 2.75764912 avg ulp diff,
- * 232 max ulp.
- *
- * ulp histogram:
- * 0 = 87.81%
- * 1 = 4.18%
- */
- float r = 1.33336498402e-3f;
- r = madd(x, r, 9.810352697968e-3f);
- r = madd(x, r, 5.551834031939e-2f);
- r = madd(x, r, 0.2401793301105f);
- r = madd(x, r, 0.693144857883f);
- r = madd(x, r, 1.0f);
- /* Multiply by 2 ^ m by adding in the exponent. */
- /* NOTE: left-shift of negative number is undefined behavior. */
- return __uint_as_float(__float_as_uint(r) + ((unsigned)m << 23));
-}
-
-ccl_device_inline float fast_expf(float x)
-{
- /* Examined 2237485550 values of exp on [-87.3300018,87.3300018]:
- * 2.6666452 avg ulp diff, 230 max ulp.
- */
- return fast_exp2f(x / M_LN2_F);
-}
-
-#if defined(__KERNEL_CPU__) && !defined(_MSC_VER)
-/* MSVC seems to have a code-gen bug here in at least SSE41/AVX, see
- * T78047 and T78869 for details. Just disable for now, it only makes
- * a small difference in denoising performance. */
-ccl_device float4 fast_exp2f4(float4 x)
-{
- const float4 one = make_float4(1.0f);
- const float4 limit = make_float4(126.0f);
- x = clamp(x, -limit, limit);
- int4 m = make_int4(x);
- x = one - (one - (x - make_float4(m)));
- float4 r = make_float4(1.33336498402e-3f);
- r = madd4(x, r, make_float4(9.810352697968e-3f));
- r = madd4(x, r, make_float4(5.551834031939e-2f));
- r = madd4(x, r, make_float4(0.2401793301105f));
- r = madd4(x, r, make_float4(0.693144857883f));
- r = madd4(x, r, make_float4(1.0f));
- return __int4_as_float4(__float4_as_int4(r) + (m << 23));
-}
-
-ccl_device_inline float4 fast_expf4(float4 x)
-{
- return fast_exp2f4(x / M_LN2_F);
-}
-#else
-ccl_device_inline float4 fast_expf4(float4 x)
-{
- return make_float4(fast_expf(x.x), fast_expf(x.y), fast_expf(x.z), fast_expf(x.w));
-}
-#endif
-
-ccl_device_inline float fast_exp10(float x)
-{
- /* Examined 2217701018 values of exp10 on [-37.9290009,37.9290009]:
- * 2.71732409 avg ulp diff, 232 max ulp.
- */
- return fast_exp2f(x * M_LN10_F / M_LN2_F);
-}
-
-ccl_device_inline float fast_expm1f(float x)
-{
- if (fabsf(x) < 1e-5f) {
- x = 1.0f - (1.0f - x); /* Crush denormals. */
- return madd(0.5f, x * x, x);
- }
- else {
- return fast_expf(x) - 1.0f;
- }
-}
-
-ccl_device float fast_sinhf(float x)
-{
- float a = fabsf(x);
- if (a > 1.0f) {
- /* Examined 53389559 values of sinh on [1,87.3300018]:
- * 33.6886442 avg ulp diff, 178 max ulp. */
- float e = fast_expf(a);
- return copysignf(0.5f * e - 0.5f / e, x);
- }
- else {
- a = 1.0f - (1.0f - a); /* Crush denorms. */
- float a2 = a * a;
- /* Degree 7 polynomial generated with sollya. */
- /* Examined 2130706434 values of sinh on [-1,1]: 1.19209e-07 max error. */
- float r = 2.03945513931e-4f;
- r = madd(r, a2, 8.32990277558e-3f);
- r = madd(r, a2, 0.1666673421859f);
- r = madd(r * a, a2, a);
- return copysignf(r, x);
- }
-}
-
-ccl_device_inline float fast_coshf(float x)
-{
- /* Examined 2237485550 values of cosh on [-87.3300018,87.3300018]:
- * 1.78256726 avg ulp diff, 178 max ulp.
- */
- float e = fast_expf(fabsf(x));
- return 0.5f * e + 0.5f / e;
-}
-
-ccl_device_inline float fast_tanhf(float x)
-{
- /* Examined 4278190080 values of tanh on [-3.40282347e+38,3.40282347e+38]:
- * 3.12924e-06 max error.
- */
- /* NOTE: ulp error is high because of sub-optimal handling around the origin. */
- float e = fast_expf(2.0f * fabsf(x));
- return copysignf(1.0f - 2.0f / (1.0f + e), x);
-}
-
-ccl_device float fast_safe_powf(float x, float y)
-{
- if (y == 0)
- return 1.0f; /* x^1=1 */
- if (x == 0)
- return 0.0f; /* 0^y=0 */
- float sign = 1.0f;
- if (x < 0.0f) {
- /* if x is negative, only deal with integer powers
- * powf returns NaN for non-integers, we will return 0 instead.
- */
- int ybits = __float_as_int(y) & 0x7fffffff;
- if (ybits >= 0x4b800000) {
- // always even int, keep positive
- }
- else if (ybits >= 0x3f800000) {
- /* Bigger than 1, check. */
- int k = (ybits >> 23) - 127; /* Get exponent. */
- int j = ybits >> (23 - k); /* Shift out possible fractional bits. */
- if ((j << (23 - k)) == ybits) { /* rebuild number and check for a match. */
- /* +1 for even, -1 for odd. */
- sign = __int_as_float(0x3f800000 | (j << 31));
- }
- else {
- /* Not an integer. */
- return 0.0f;
- }
- }
- else {
- /* Not an integer. */
- return 0.0f;
- }
- }
- return sign * fast_exp2f(y * fast_log2f(fabsf(x)));
-}
-
-/* TODO(sergey): Check speed with our erf functions implementation from
- * bsdf_microfacet.h.
- */
-
-ccl_device_inline float fast_erff(float x)
-{
- /* Examined 1082130433 values of erff on [0,4]: 1.93715e-06 max error. */
- /* Abramowitz and Stegun, 7.1.28. */
- const float a1 = 0.0705230784f;
- const float a2 = 0.0422820123f;
- const float a3 = 0.0092705272f;
- const float a4 = 0.0001520143f;
- const float a5 = 0.0002765672f;
- const float a6 = 0.0000430638f;
- const float a = fabsf(x);
- if (a >= 12.3f) {
- return copysignf(1.0f, x);
- }
- const float b = 1.0f - (1.0f - a); /* Crush denormals. */
- const float r = madd(
- madd(madd(madd(madd(madd(a6, b, a5), b, a4), b, a3), b, a2), b, a1), b, 1.0f);
- const float s = r * r; /* ^2 */
- const float t = s * s; /* ^4 */
- const float u = t * t; /* ^8 */
- const float v = u * u; /* ^16 */
- return copysignf(1.0f - 1.0f / v, x);
-}
-
-ccl_device_inline float fast_erfcf(float x)
-{
- /* Examined 2164260866 values of erfcf on [-4,4]: 1.90735e-06 max error.
- *
- * ulp histogram:
- *
- * 0 = 80.30%
- */
- return 1.0f - fast_erff(x);
-}
-
-ccl_device_inline float fast_ierff(float x)
-{
- /* From: Approximating the `erfinv` function by Mike Giles. */
- /* To avoid trouble at the limit, clamp input to 1-eps. */
- float a = fabsf(x);
- if (a > 0.99999994f) {
- a = 0.99999994f;
- }
- float w = -fast_logf((1.0f - a) * (1.0f + a)), p;
- if (w < 5.0f) {
- w = w - 2.5f;
- p = 2.81022636e-08f;
- p = madd(p, w, 3.43273939e-07f);
- p = madd(p, w, -3.5233877e-06f);
- p = madd(p, w, -4.39150654e-06f);
- p = madd(p, w, 0.00021858087f);
- p = madd(p, w, -0.00125372503f);
- p = madd(p, w, -0.00417768164f);
- p = madd(p, w, 0.246640727f);
- p = madd(p, w, 1.50140941f);
- }
- else {
- w = sqrtf(w) - 3.0f;
- p = -0.000200214257f;
- p = madd(p, w, 0.000100950558f);
- p = madd(p, w, 0.00134934322f);
- p = madd(p, w, -0.00367342844f);
- p = madd(p, w, 0.00573950773f);
- p = madd(p, w, -0.0076224613f);
- p = madd(p, w, 0.00943887047f);
- p = madd(p, w, 1.00167406f);
- p = madd(p, w, 2.83297682f);
- }
- return p * x;
-}
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_FAST_MATH__ */
diff --git a/intern/cycles/util/util_math_float2.h b/intern/cycles/util/util_math_float2.h
deleted file mode 100644
index 70b80c33544..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, 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 30a1b4c3f77..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, 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, 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 19af5c8c638..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(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_math_intersect.h b/intern/cycles/util/util_math_intersect.h
deleted file mode 100644
index fd0c9124345..00000000000
--- a/intern/cycles/util/util_math_intersect.h
+++ /dev/null
@@ -1,249 +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_INTERSECT_H__
-#define __UTIL_MATH_INTERSECT_H__
-
-CCL_NAMESPACE_BEGIN
-
-/* Ray Intersection */
-
-ccl_device bool ray_sphere_intersect(float3 ray_P,
- float3 ray_D,
- float ray_t,
- float3 sphere_P,
- float sphere_radius,
- float3 *isect_P,
- float *isect_t)
-{
- const float3 d = sphere_P - ray_P;
- const float radiussq = sphere_radius * sphere_radius;
- const float tsq = dot(d, d);
-
- if (tsq > radiussq) {
- /* Ray origin outside sphere. */
- const float tp = dot(d, ray_D);
- if (tp < 0.0f) {
- /* Ray points away from sphere. */
- return false;
- }
- const float dsq = tsq - tp * tp; /* Pythagoras. */
- if (dsq > radiussq) {
- /* Closest point on ray outside sphere. */
- return false;
- }
- const float t = tp - sqrtf(radiussq - dsq); /* pythagoras */
- if (t < ray_t) {
- *isect_t = t;
- *isect_P = ray_P + ray_D * t;
- return true;
- }
- }
- return false;
-}
-
-ccl_device bool ray_aligned_disk_intersect(float3 ray_P,
- float3 ray_D,
- float ray_t,
- float3 disk_P,
- float disk_radius,
- float3 *isect_P,
- float *isect_t)
-{
- /* Aligned disk normal. */
- float disk_t;
- const float3 disk_N = normalize_len(ray_P - disk_P, &disk_t);
- const float div = dot(ray_D, disk_N);
- if (UNLIKELY(div == 0.0f)) {
- return false;
- }
- /* Compute t to intersection point. */
- const float t = -disk_t / div;
- if (t < 0.0f || t > ray_t) {
- return false;
- }
- /* Test if within radius. */
- float3 P = ray_P + ray_D * t;
- if (len_squared(P - disk_P) > disk_radius * disk_radius) {
- return false;
- }
- *isect_P = P;
- *isect_t = t;
- return true;
-}
-
-ccl_device_forceinline bool ray_triangle_intersect(float3 ray_P,
- float3 ray_dir,
- float ray_t,
-#if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__)
- const ssef *ssef_verts,
-#else
- const float3 tri_a,
- const float3 tri_b,
- const float3 tri_c,
-#endif
- float *isect_u,
- float *isect_v,
- float *isect_t)
-{
-#if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__)
- typedef ssef float3;
- const float3 tri_a(ssef_verts[0]);
- const float3 tri_b(ssef_verts[1]);
- const float3 tri_c(ssef_verts[2]);
- const float3 P(ray_P);
- const float3 dir(ray_dir);
-#else
-# define dot3(a, b) dot(a, b)
- const float3 P = ray_P;
- const float3 dir = ray_dir;
-#endif
-
- /* Calculate vertices relative to ray origin. */
- const float3 v0 = tri_c - P;
- const float3 v1 = tri_a - P;
- const float3 v2 = tri_b - P;
-
- /* Calculate triangle edges. */
- const float3 e0 = v2 - v0;
- const float3 e1 = v0 - v1;
- const float3 e2 = v1 - v2;
-
- /* Perform edge tests. */
-#if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__)
- const float3 crossU = cross(v2 + v0, e0);
- const float3 crossV = cross(v0 + v1, e1);
- const float3 crossW = cross(v1 + v2, e2);
-
- ssef crossX(crossU);
- ssef crossY(crossV);
- ssef crossZ(crossW);
- ssef zero = _mm_setzero_ps();
- _MM_TRANSPOSE4_PS(crossX, crossY, crossZ, zero);
-
- const ssef dirX(ray_dir.x);
- const ssef dirY(ray_dir.y);
- const ssef dirZ(ray_dir.z);
-
- ssef UVWW = madd(crossX, dirX, madd(crossY, dirY, crossZ * dirZ));
-#else /* __KERNEL_SSE2__ */
- const float U = dot(cross(v2 + v0, e0), ray_dir);
- const float V = dot(cross(v0 + v1, e1), ray_dir);
- const float W = dot(cross(v1 + v2, e2), ray_dir);
-#endif /* __KERNEL_SSE2__ */
-
-#if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__)
- int uvw_sign = movemask(UVWW) & 0x7;
- if (uvw_sign != 0) {
- if (uvw_sign != 0x7) {
- return false;
- }
- }
-#else
- const float minUVW = min(U, min(V, W));
- const float maxUVW = max(U, max(V, W));
-
- if (minUVW < 0.0f && maxUVW > 0.0f) {
- return false;
- }
-#endif
-
- /* Calculate geometry normal and denominator. */
- const float3 Ng1 = cross(e1, e0);
- // const Vec3vfM Ng1 = stable_triangle_normal(e2,e1,e0);
- const float3 Ng = Ng1 + Ng1;
- const float den = dot3(Ng, dir);
- /* Avoid division by 0. */
- if (UNLIKELY(den == 0.0f)) {
- return false;
- }
-
- /* Perform depth test. */
- const float T = dot3(v0, Ng);
- const int sign_den = (__float_as_int(den) & 0x80000000);
- const float sign_T = xor_signmask(T, sign_den);
- if ((sign_T < 0.0f) || (sign_T > ray_t * xor_signmask(den, sign_den))) {
- return false;
- }
-
- const float inv_den = 1.0f / den;
-#if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__)
- UVWW *= inv_den;
- _mm_store_ss(isect_u, UVWW);
- _mm_store_ss(isect_v, shuffle<1, 1, 3, 3>(UVWW));
-#else
- *isect_u = U * inv_den;
- *isect_v = V * inv_den;
-#endif
- *isect_t = T * inv_den;
- return true;
-
-#undef dot3
-}
-
-/* Tests for an intersection between a ray and a quad defined by
- * its midpoint, normal and sides.
- * If ellipse is true, hits outside the ellipse that's enclosed by the
- * quad are rejected.
- */
-ccl_device bool ray_quad_intersect(float3 ray_P,
- float3 ray_D,
- float ray_mint,
- float ray_maxt,
- float3 quad_P,
- float3 quad_u,
- float3 quad_v,
- float3 quad_n,
- float3 *isect_P,
- float *isect_t,
- float *isect_u,
- float *isect_v,
- bool ellipse)
-{
- /* Perform intersection test. */
- float t = -(dot(ray_P, quad_n) - dot(quad_P, quad_n)) / dot(ray_D, quad_n);
- if (t < ray_mint || t > ray_maxt) {
- return false;
- }
- const float3 hit = ray_P + t * ray_D;
- const float3 inplane = hit - quad_P;
- const float u = dot(inplane, quad_u) / dot(quad_u, quad_u);
- if (u < -0.5f || u > 0.5f) {
- return false;
- }
- const float v = dot(inplane, quad_v) / dot(quad_v, quad_v);
- if (v < -0.5f || v > 0.5f) {
- return false;
- }
- if (ellipse && (u * u + v * v > 0.25f)) {
- return false;
- }
- /* Store the result. */
- /* TODO(sergey): Check whether we can avoid some checks here. */
- if (isect_P != NULL)
- *isect_P = hit;
- if (isect_t != NULL)
- *isect_t = t;
- if (isect_u != NULL)
- *isect_u = u + 0.5f;
- if (isect_v != NULL)
- *isect_v = v + 0.5f;
- return true;
-}
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_MATH_INTERSECT_H__ */
diff --git a/intern/cycles/util/util_math_matrix.h b/intern/cycles/util/util_math_matrix.h
deleted file mode 100644
index 123736f75a6..00000000000
--- a/intern/cycles/util/util_math_matrix.h
+++ /dev/null
@@ -1,448 +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_MATRIX_H__
-#define __UTIL_MATH_MATRIX_H__
-
-CCL_NAMESPACE_BEGIN
-
-#define MAT(A, size, row, col) A[(row) * (size) + (col)]
-
-/* Variants that use a constant stride on GPUS. */
-#ifdef __KERNEL_GPU__
-# define MATS(A, n, r, c, s) A[((r) * (n) + (c)) * (s)]
-/* Element access when only the lower-triangular elements are stored. */
-# define MATHS(A, r, c, s) A[((r) * ((r) + 1) / 2 + (c)) * (s)]
-# define VECS(V, i, s) V[(i) * (s)]
-#else
-# define MATS(A, n, r, c, s) MAT(A, n, r, c)
-# define MATHS(A, r, c, s) A[(r) * ((r) + 1) / 2 + (c)]
-# define VECS(V, i, s) V[i]
-#endif
-
-/* Zeroing helpers. */
-
-ccl_device_inline void math_vector_zero(float *v, int n)
-{
- for (int i = 0; i < n; i++) {
- v[i] = 0.0f;
- }
-}
-
-ccl_device_inline void math_matrix_zero(float *A, int n)
-{
- for (int row = 0; row < n; row++) {
- for (int col = 0; col <= row; col++) {
- MAT(A, n, row, col) = 0.0f;
- }
- }
-}
-
-/* Elementary vector operations. */
-
-ccl_device_inline void math_vector_add(float *a, const float *ccl_restrict b, int n)
-{
- for (int i = 0; i < n; i++) {
- a[i] += b[i];
- }
-}
-
-ccl_device_inline void math_vector_mul(float *a, const float *ccl_restrict b, int n)
-{
- for (int i = 0; i < n; i++) {
- a[i] *= b[i];
- }
-}
-
-ccl_device_inline void math_vector_mul_strided(ccl_global float *a,
- const float *ccl_restrict b,
- int astride,
- int n)
-{
- for (int i = 0; i < n; i++) {
- a[i * astride] *= b[i];
- }
-}
-
-ccl_device_inline void math_vector_scale(float *a, float b, int n)
-{
- for (int i = 0; i < n; i++) {
- a[i] *= b;
- }
-}
-
-ccl_device_inline void math_vector_max(float *a, const float *ccl_restrict b, int n)
-{
- for (int i = 0; i < n; i++) {
- a[i] = max(a[i], b[i]);
- }
-}
-
-ccl_device_inline void math_vec3_add(float3 *v, int n, float *x, float3 w)
-{
- for (int i = 0; i < n; i++) {
- v[i] += w * x[i];
- }
-}
-
-ccl_device_inline void math_vec3_add_strided(
- ccl_global float3 *v, int n, float *x, float3 w, int stride)
-{
- for (int i = 0; i < n; i++) {
- ccl_global float *elem = (ccl_global float *)(v + i * stride);
- atomic_add_and_fetch_float(elem + 0, w.x * x[i]);
- atomic_add_and_fetch_float(elem + 1, w.y * x[i]);
- atomic_add_and_fetch_float(elem + 2, w.z * x[i]);
- }
-}
-
-/* Elementary matrix operations.
- * Note: TriMatrix refers to a square matrix that is symmetric,
- * and therefore its upper-triangular part isn't stored. */
-
-ccl_device_inline void math_trimatrix_add_diagonal(ccl_global float *A,
- int n,
- float val,
- int stride)
-{
- for (int row = 0; row < n; row++) {
- MATHS(A, row, row, stride) += val;
- }
-}
-
-/* Add Gramian matrix of v to A.
- * The Gramian matrix of v is vt*v, so element (i,j) is v[i]*v[j]. */
-ccl_device_inline void math_matrix_add_gramian(float *A,
- int n,
- const float *ccl_restrict v,
- float weight)
-{
- for (int row = 0; row < n; row++) {
- for (int col = 0; col <= row; col++) {
- MAT(A, n, row, col) += v[row] * v[col] * weight;
- }
- }
-}
-
-/* Add Gramian matrix of v to A.
- * The Gramian matrix of v is vt*v, so element (i,j) is v[i]*v[j]. */
-ccl_device_inline void math_trimatrix_add_gramian_strided(
- ccl_global float *A, int n, const float *ccl_restrict v, float weight, int stride)
-{
- for (int row = 0; row < n; row++) {
- for (int col = 0; col <= row; col++) {
- atomic_add_and_fetch_float(&MATHS(A, row, col, stride), v[row] * v[col] * weight);
- }
- }
-}
-
-ccl_device_inline void math_trimatrix_add_gramian(ccl_global float *A,
- int n,
- const float *ccl_restrict v,
- float weight)
-{
- for (int row = 0; row < n; row++) {
- for (int col = 0; col <= row; col++) {
- MATHS(A, row, col, 1) += v[row] * v[col] * weight;
- }
- }
-}
-
-/* Transpose matrix A in place. */
-ccl_device_inline void math_matrix_transpose(ccl_global float *A, int n, int stride)
-{
- for (int i = 0; i < n; i++) {
- for (int j = 0; j < i; j++) {
- float temp = MATS(A, n, i, j, stride);
- MATS(A, n, i, j, stride) = MATS(A, n, j, i, stride);
- MATS(A, n, j, i, stride) = temp;
- }
- }
-}
-
-/* Solvers for matrix problems */
-
-/* In-place Cholesky-Banachiewicz decomposition of the square, positive-definite matrix A
- * into a lower triangular matrix L so that A = L*L^T. A is being overwritten by L.
- * Also, only the lower triangular part of A is ever accessed. */
-ccl_device void math_trimatrix_cholesky(ccl_global float *A, int n, int stride)
-{
- for (int row = 0; row < n; row++) {
- for (int col = 0; col <= row; col++) {
- float sum_col = MATHS(A, row, col, stride);
- for (int k = 0; k < col; k++) {
- sum_col -= MATHS(A, row, k, stride) * MATHS(A, col, k, stride);
- }
- if (row == col) {
- sum_col = sqrtf(max(sum_col, 0.0f));
- }
- else {
- sum_col /= MATHS(A, col, col, stride);
- }
- MATHS(A, row, col, stride) = sum_col;
- }
- }
-}
-
-/* Solve A*S=y for S given A and y,
- * where A is symmetrical positive-semi-definite and both inputs are destroyed in the process.
- *
- * We can apply Cholesky decomposition to find a lower triangular L so that L*Lt = A.
- * With that we get (L*Lt)*S = L*(Lt*S) = L*b = y, defining b as Lt*S.
- * Since L is lower triangular, finding b is relatively easy since y is known.
- * Then, the remaining problem is Lt*S = b, which again can be solved easily.
- *
- * This is useful for solving the normal equation S=inv(Xt*W*X)*Xt*W*y, since Xt*W*X is
- * symmetrical positive-semidefinite by construction,
- * so we can just use this function with A=Xt*W*X and y=Xt*W*y. */
-ccl_device_inline void math_trimatrix_vec3_solve(ccl_global float *A,
- ccl_global float3 *y,
- int n,
- int stride)
-{
- /* Since the first entry of the design row is always 1, the upper-left element of XtWX is a good
- * heuristic for the amount of pixels considered (with weighting),
- * therefore the amount of correction is scaled based on it. */
- math_trimatrix_add_diagonal(A, n, 3e-7f * A[0], stride); /* Improve the numerical stability. */
- math_trimatrix_cholesky(A, n, stride); /* Replace A with L so that L*Lt = A. */
-
- /* Use forward substitution to solve L*b = y, replacing y by b. */
- for (int row = 0; row < n; row++) {
- float3 sum = VECS(y, row, stride);
- for (int col = 0; col < row; col++)
- sum -= MATHS(A, row, col, stride) * VECS(y, col, stride);
- VECS(y, row, stride) = sum / MATHS(A, row, row, stride);
- }
-
- /* Use backward substitution to solve Lt*S = b, replacing b by S. */
- for (int row = n - 1; row >= 0; row--) {
- float3 sum = VECS(y, row, stride);
- for (int col = row + 1; col < n; col++)
- sum -= MATHS(A, col, row, stride) * VECS(y, col, stride);
- VECS(y, row, stride) = sum / MATHS(A, row, row, stride);
- }
-}
-
-/* Perform the Jacobi Eigenvalue Method on matrix A.
- * A is assumed to be a symmetrical matrix, therefore only the lower-triangular part is ever
- * accessed. The algorithm overwrites the contents of A.
- *
- * After returning, A will be overwritten with D, which is (almost) diagonal,
- * and V will contain the eigenvectors of the original A in its rows (!),
- * so that A = V^T*D*V. Therefore, the diagonal elements of D are the (sorted) eigenvalues of A.
- */
-ccl_device void math_matrix_jacobi_eigendecomposition(float *A,
- ccl_global float *V,
- int n,
- int v_stride)
-{
- const float singular_epsilon = 1e-9f;
-
- for (int row = 0; row < n; row++) {
- for (int col = 0; col < n; col++) {
- MATS(V, n, row, col, v_stride) = (col == row) ? 1.0f : 0.0f;
- }
- }
-
- for (int sweep = 0; sweep < 8; sweep++) {
- float off_diagonal = 0.0f;
- for (int row = 1; row < n; row++) {
- for (int col = 0; col < row; col++) {
- off_diagonal += fabsf(MAT(A, n, row, col));
- }
- }
- if (off_diagonal < 1e-7f) {
- /* The matrix has nearly reached diagonal form.
- * Since the eigenvalues are only used to determine truncation, their exact values aren't
- * required - a relative error of a few ULPs won't matter at all. */
- break;
- }
-
- /* Set the threshold for the small element rotation skip in the first sweep:
- * Skip all elements that are less than a tenth of the average off-diagonal element. */
- float threshold = 0.2f * off_diagonal / (n * n);
-
- for (int row = 1; row < n; row++) {
- for (int col = 0; col < row; col++) {
- /* Perform a Jacobi rotation on this element that reduces it to zero. */
- float element = MAT(A, n, row, col);
- float abs_element = fabsf(element);
-
- /* If we're in a later sweep and the element already is very small,
- * just set it to zero and skip the rotation. */
- if (sweep > 3 && abs_element <= singular_epsilon * fabsf(MAT(A, n, row, row)) &&
- abs_element <= singular_epsilon * fabsf(MAT(A, n, col, col))) {
- MAT(A, n, row, col) = 0.0f;
- continue;
- }
-
- if (element == 0.0f) {
- continue;
- }
-
- /* If we're in one of the first sweeps and the element is smaller than the threshold,
- * skip it. */
- if (sweep < 3 && (abs_element < threshold)) {
- continue;
- }
-
- /* Determine rotation: The rotation is characterized by its angle phi - or,
- * in the actual implementation, sin(phi) and cos(phi).
- * To find those, we first compute their ratio - that might be unstable if the angle
- * approaches 90°, so there's a fallback for that case.
- * Then, we compute sin(phi) and cos(phi) themselves. */
- float singular_diff = MAT(A, n, row, row) - MAT(A, n, col, col);
- float ratio;
- if (abs_element > singular_epsilon * fabsf(singular_diff)) {
- float cot_2phi = 0.5f * singular_diff / element;
- ratio = 1.0f / (fabsf(cot_2phi) + sqrtf(1.0f + cot_2phi * cot_2phi));
- if (cot_2phi < 0.0f)
- ratio = -ratio; /* Copy sign. */
- }
- else {
- ratio = element / singular_diff;
- }
-
- float c = 1.0f / sqrtf(1.0f + ratio * ratio);
- float s = ratio * c;
- /* To improve numerical stability by avoiding cancellation, the update equations are
- * reformulized to use sin(phi) and tan(phi/2) instead. */
- float tan_phi_2 = s / (1.0f + c);
-
- /* Update the singular values in the diagonal. */
- float singular_delta = ratio * element;
- MAT(A, n, row, row) += singular_delta;
- MAT(A, n, col, col) -= singular_delta;
-
- /* Set the element itself to zero. */
- MAT(A, n, row, col) = 0.0f;
-
- /* Perform the actual rotations on the matrices. */
-#define ROT(M, r1, c1, r2, c2, stride) \
- { \
- float M1 = MATS(M, n, r1, c1, stride); \
- float M2 = MATS(M, n, r2, c2, stride); \
- MATS(M, n, r1, c1, stride) -= s * (M2 + tan_phi_2 * M1); \
- MATS(M, n, r2, c2, stride) += s * (M1 - tan_phi_2 * M2); \
- }
-
- /* Split into three parts to ensure correct accesses since we only store the
- * lower-triangular part of A. */
- for (int i = 0; i < col; i++)
- ROT(A, col, i, row, i, 1);
- for (int i = col + 1; i < row; i++)
- ROT(A, i, col, row, i, 1);
- for (int i = row + 1; i < n; i++)
- ROT(A, i, col, i, row, 1);
-
- for (int i = 0; i < n; i++)
- ROT(V, col, i, row, i, v_stride);
-#undef ROT
- }
- }
- }
-
- /* Sort eigenvalues and the associated eigenvectors. */
- for (int i = 0; i < n - 1; i++) {
- float v = MAT(A, n, i, i);
- int k = i;
- for (int j = i; j < n; j++) {
- if (MAT(A, n, j, j) >= v) {
- v = MAT(A, n, j, j);
- k = j;
- }
- }
- if (k != i) {
- /* Swap eigenvalues. */
- MAT(A, n, k, k) = MAT(A, n, i, i);
- MAT(A, n, i, i) = v;
- /* Swap eigenvectors. */
- for (int j = 0; j < n; j++) {
- float v = MATS(V, n, i, j, v_stride);
- MATS(V, n, i, j, v_stride) = MATS(V, n, k, j, v_stride);
- MATS(V, n, k, j, v_stride) = v;
- }
- }
- }
-}
-
-#ifdef __KERNEL_SSE3__
-ccl_device_inline void math_vector_zero_sse(float4 *A, int n)
-{
- for (int i = 0; i < n; i++) {
- A[i] = make_float4(0.0f);
- }
-}
-
-ccl_device_inline void math_matrix_zero_sse(float4 *A, int n)
-{
- for (int row = 0; row < n; row++) {
- for (int col = 0; col <= row; col++) {
- MAT(A, n, row, col) = make_float4(0.0f);
- }
- }
-}
-
-/* Add Gramian matrix of v to A.
- * The Gramian matrix of v is v^T*v, so element (i,j) is v[i]*v[j]. */
-ccl_device_inline void math_matrix_add_gramian_sse(float4 *A,
- int n,
- const float4 *ccl_restrict v,
- float4 weight)
-{
- for (int row = 0; row < n; row++) {
- for (int col = 0; col <= row; col++) {
- MAT(A, n, row, col) = MAT(A, n, row, col) + v[row] * v[col] * weight;
- }
- }
-}
-
-ccl_device_inline void math_vector_add_sse(float4 *V, int n, const float4 *ccl_restrict a)
-{
- for (int i = 0; i < n; i++) {
- V[i] += a[i];
- }
-}
-
-ccl_device_inline void math_vector_mul_sse(float4 *V, int n, const float4 *ccl_restrict a)
-{
- for (int i = 0; i < n; i++) {
- V[i] *= a[i];
- }
-}
-
-ccl_device_inline void math_vector_max_sse(float4 *a, const float4 *ccl_restrict b, int n)
-{
- for (int i = 0; i < n; i++) {
- a[i] = max(a[i], b[i]);
- }
-}
-
-ccl_device_inline void math_matrix_hsum(float *A, int n, const float4 *ccl_restrict B)
-{
- for (int row = 0; row < n; row++) {
- for (int col = 0; col <= row; col++) {
- MAT(A, n, row, col) = reduce_add(MAT(B, n, row, col))[0];
- }
- }
-}
-#endif
-
-#undef MAT
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_MATH_MATRIX_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 9c7e0061c82..00000000000
--- a/intern/cycles/util/util_projection.h
+++ /dev/null
@@ -1,216 +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(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(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 36f02a01f7b..00000000000
--- a/intern/cycles/util/util_rect.h
+++ /dev/null
@@ -1,72 +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, int *x, 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 9c0b2ca50bb..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 e9cd3b0b483..00000000000
--- a/intern/cycles/util/util_transform.h
+++ /dev/null
@@ -1,510 +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(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(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(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(Transform *tfm, 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 ccl_global 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 ccl_global DecomposedTransform *a = motion + step;
- const ccl_global 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(Transform *tfm)
-{
- return isfinite4_safe(tfm->x) && isfinite4_safe(tfm->y) && isfinite4_safe(tfm->z);
-}
-
-ccl_device_inline bool transform_decomposed_isfinite_safe(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